Java 线程(多线程)详解

查看了许多书籍,网上的博客,现在我来说一下有关于我对线程的详解,有不对的欢迎指正。

一. 线程的生命周期:

程序有自己的一个生命周期,线程也不例外,也有自己的生命周期。查看许多书籍或者网上资料,发现了一件很有趣的事情,那就是它们对线程的生命周期不是唯一。有两种或者以上的线程生命周期。

第一种线程生命周期线程状态转换图:一共5个状态:新建,就绪,运行,阻塞和结束

                        图 1

第二种生命周期图:一共6个状态:New,Runnable,Blocked,Waiting,Timed Waiting,Terminated

图 二

事实上,从java源码得知的是,线程的生命周期是属于第二种生命周期的,当然也不能说明除第二种生命周期,其余的生命周期是错的,只能说每种线程生命周期都是为了让学者更好的理解线程的状态。下面我说一下我对线程生命周期的理解,仅限参考:

1. 当Thread对象被创建时,该线程的状态便是新建状态

2. 当线程调用start()方法并调用时,该线程状态由新建状态进入了运行状态。

运行状态可以分为可运行状态和运行状态,对应图1的就绪状态和运行状态。当调用start()方法时,cpu要给予线程资源,当线程还未获得cpu资源,线程无法运行或者该线程获取了cpu资源,但未开始运行时,该线程状态称作为’可运行状态’,若线程获取cpu资源时,且线程运行线程执行体(run方法中的代码块),对应的状态便是’运行状态’。事实上,我们无法通过程序将线程’可运行状态’和’运行状态分离’出来,因此’可运行状态’对于开发者来说,是不存在的。

3. 当线程执行完毕后,线程便进入了结束的状态。当然,线程进入结束状态不仅仅只是线程执行完毕,还有线程执行过程中出现程序错误或者线程被程序强行结束(Thread.stop方法,可以让线程直接进入结束状态),这些都会让线程进入结束状态。

4. 除了上述说的3种状态,还有一种状态叫做阻塞状态。该状态是线程运行时,遇到指定的方法,该线程运行停止下来,那么该线程状态叫做阻塞状态。该状态是线程的重点,线程控制也是根据该状态而展开的。

二.线程控制:

说到线程控制,不得不提的便是多线程以及线程并发。何为多线程,当单一的线程运行时,称之为单线程,多条线程运行时,则称之为多线程。而线程并发,指的是同一时间,cpu同时处理多个线程。然而cpu并发线程的数量是(cpu物理线程数)有限的,而线程的创建则是无限的,当创建出来的线程数,已经超多了cpu物理线程数时,cpu本着雨露均沾的做法,先让给予对应cpu物理线程数的线程资源,并让这些线程运行一段时间,当运行时间到时,cpu会剥夺这些线程的资源,并给予另外一批对应cpu物理线程数的线程资源(该批线程中,可能有些线程和上一批是一样的),让其运行一段时间。周而复始,直到所有的线程运行结束。

class TestThread implements Runnable{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread()+" "+i);
        }
    }
}
public class Threads{
    public static void main(String[] args){
        TestThread testThread = new TestThread();
        for(int i=0;i<5;i++){
            Thread t = new Thread(testThread);
            t.start();
        }
    }
}    

上述代码我们创建了3个线程(3个线程所运行的线程执行体是一致的),并同时运行

结果一:

Thread[Thread-0,5,main] 0
Thread[Thread-3,5,main] 0
Thread[Thread-4,5,main] 0
Thread[Thread-4,5,main] 1
Thread[Thread-2,5,main] 0
Thread[Thread-1,5,main] 0
Thread[Thread-2,5,main] 1
Thread[Thread-4,5,main] 2
Thread[Thread-3,5,main] 1
Thread[Thread-0,5,main] 1

结果二:

Thread[Thread-1,5,main] 0
Thread[Thread-0,5,main] 0
Thread[Thread-1,5,main] 1
Thread[Thread-0,5,main] 1
Thread[Thread-1,5,main] 2
Thread[Thread-2,5,main] 0
Thread[Thread-0,5,main] 2
Thread[Thread-2,5,main] 1
Thread[Thread-1,5,main] 3
Thread[Thread-2,5,main] 2

我们根据结果一与结果二做对比,我们不难发现,运行出来的结果是不一致的,而这导致运行出来的结果不一致的原因则是因为cpu给予线程资源是根据cpu的’喜好’,同时该线程不是立刻执行完毕(由于这里执行的内容比较多,线程不能立刻执行完),而是执行到了一部分时,换成的另外一个线程执行。这也说明了cpu本着雨露均沾的做法,来实现多线程并发。

由于多线程的运行结果的不唯一,多线程的启动线程随意,会让数据发生丢失的可能,在程序上,再对要求结果要唯一的情况下,这是不允许的事情,因此我们要控制线程的状态,让运行结果变得唯一,让线程变得安全。以下是线程控制的几种类型:

  1. 改变线程优先度
  2. 线程停止运行方法
  3. 线程同步
  4. 线程通信

改变线程优先度:

当线程优先度最高时,cpu越喜欢,会优先给予资源,并让线程运行,当然当线程优先度相同时,cpu也只能随机选线程。对应方法:Thread.setPriorty(int),int参数范围为0-10,0优先度最低,1优先度最高

我们根据上述代码进行优化,代码如下:

class TestThread implements Runnable{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread()+" "+i);
        }
    }
}
public class Threads{
    public static void main(String[] args){
        TestThread testThread = new TestThread();
        /**
         * 线程优先级设置
         * */
        Thread t_1 = new Thread(testThread);
        Thread t_2 = new Thread(testThread);
        Thread t_3 = new Thread(testThread);
        Thread t_4 = new Thread(testThread);
        Thread t_5 = new Thread(testThread);
        t_5.setPriority(10);
        t_5.start();t_1.start();t_2.start();t_3.start();t_4.start();
    }
}   

值得注意的是,尽管cpu会优先执行优先级别高的线程,但在程序中,代码会有执行的先后顺序,代码执行也需要时间,尽管这段时间我们不可能察觉,因为时间太短了,几毫秒的时间,但对于cpu来说,以及可以给予线程资源并让线程运行一段时间了,同时cpu虽然会优先执行优先级别高的线程,但也不是说一定会优先执行优先级别高的线程,只能说大概率的会优先执行,以下是运行结果前十行。

设置了优先级别高的线程,最大的优势在于,cpu会更倾向它,让它更快的完成运行

运行结果一:

Thread[Thread-4,10,main] 0
Thread[Thread-4,10,main] 1
Thread[Thread-0,5,main] 0
Thread[Thread-4,10,main] 2
Thread[Thread-0,5,main] 1
Thread[Thread-4,10,main] 3
Thread[Thread-0,5,main] 2
Thread[Thread-4,10,main] 4
Thread[Thread-0,5,main] 3
Thread[Thread-4,10,main] 5

运行结果二:

Thread[Thread-4,10,main] 0
Thread[Thread-1,5,main] 0
Thread[Thread-0,5,main] 0
Thread[Thread-3,5,main] 0
Thread[Thread-2,5,main] 0
Thread[Thread-1,5,main] 1
Thread[Thread-4,10,main] 1
Thread[Thread-1,5,main] 2
Thread[Thread-1,5,main] 3
Thread[Thread-2,5,main] 1

线程停止运行方法:

  1. Thread.sleep()方法,有Thread.sleep(long millis)和Thread.sleep(long millis,int nanos)选择,作用是让线程休息millis毫秒(+nanos毫微秒),并停止运行(剥夺cpu资源),当休息结束后回到线程可运行状态。该方法需要申明异常
  2. Thread.yield()方法,作用是让线程停一下,该线程从运行状态直接回到可运行状态,同时让同优先级别或以上的线程运行,并且cpu不取回该线程资源。由于cpu不取回资源,该线程会很快速进入运行状态。
  3. Thread.join()方法,该方法有Thread.join(),Thread.join(long millis)和Thread.join(long millis,int nanos)选择,作用是运行该程序的线程要等对应线程运行完毕后方可继续运行,有参数的情况是是等对应线程运行指定millis毫秒(+nanos毫微秒)后,便继续运行。      

Ps这里说明一下sleep方法与yield方法的区别:

  1. sleep执行后cpu找另外的线程运行,而yield执行后,是找优先度相同或以上的线程运行。
  2. sleep执行后,会进入阻塞的状态,而yield则是直接进入可运行状态
  3. sleep需要申明异常而yield不用
  4. sleep可移植性比yield好,因此尽可能的选择sleep方法
class TestThread implements Runnable{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread()+" "+i);
        }
    }
}
public class Threads{
    public static void main(String[] args){
        /**
         * 线程停止运行的方法
         * */
        System.out.println(Thread.currentThread()+"开始运行");
        TestThread test = new TestThread();
        Thread t_1 = new Thread(test);
        Thread t_2 = new Thread(test);
        Thread t_3 = new Thread(test);
        try{
            t_1.start();t_2.start();t_3.start();
            t_1.join();
        }catch(Exception e){}
        System.out.println(Thread.currentThread()+"停止运行");
    }
} 

上述代码中创建了3个线程,以及使用mian方法(主线程)。设置了主线程需要等待线程1运行结束后方法继续运行。大家可以去查看以下运行结果,会发现System.out.println(Thread.currentThread()+"停止运行")都是等待线程1打印完后打印的。

线程同步:

先看一下下述代码以及运行结果

/**
 * 未同步线程
 * */
class TestThreads implements Runnable{
    int n = 100;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<50;i++){
            System.out.print(Thread.currentThread() +" "+ i);
            System.out.print("\t"+Thread.currentThread().getPriority());
            System.out.print("\t当前n为:"+n);
            n--;
            System.out.println("\t售后n为"+n);
        }
    }
}
public class Threads{
    public static void main(String[] args){
        /**
         * 未同步线程
         * */
        TestThreads testThreads = new TestThreads();
        Thread t_1 = new Thread(testThreads);
        Thread t_2 = new Thread(testThreads);
        Thread t_3 = new Thread(testThreads);
        t_1.start();t_2.start();t_3.start();
        }
}

我们创建了3个线程,这三个线程都执行同一对象中的run方法,在run方法中,由四个打印语句。运行结果如下:

Thread[Thread-0,5,main] 0Thread[Thread-2,5,main] 0    5Thread[Thread-1,5,main] 0    当前n为:100    5    售后n为99
    5Thread[Thread-2,5,main] 1    5    当前n为:99    售后n为98
    当前n为:99    售后n为97
Thread[Thread-0,5,main] 1    5    当前n为:97    售后n为96
Thread[Thread-0,5,main] 2    5    当前n为:96    售后n为95
Thread[Thread-0,5,main] 3    5    当前n为:95    售后n为94
Thread[Thread-0,5,main] 4    5    当前n为:94    售后n为93
Thread[Thread-2,5,main] 2    当前n为:99    5Thread[Thread-0,5,main] 5    当前n为:92    售后n为92
    售后n为91
    5    当前n为:91Thread[Thread-2,5,main] 3    5    当前n为:90    售后n为89

我们可以看到运行的结果,非常混乱,并且该线程充满了不安全性。为了让线程有序,并且充满安全性,就需要用到线程的同步。

这里的线程同步,并非指多个线程并发同步执行。这里的同步,是指当多线程使用同一资源时,为了保证资源不混乱,并且有序的让多线程进行。线程同步的原理是,当多线程执行同一资源时,cpu只会让其中一个线程执行,当该线程执行完同步资源后,cpu会让另一个线程执行,周而复始,直到资源被用完,或者所有线程结束。你可以理解为,多人买车票的时候,需要排队买车票,可以以多线程当作多人,以车票数当作资源。网上有个网友说,线程同步,就是线程排队,实际上确实如此。而在程序中,如何能让多线程排队呢,答案是让每个线程带有锁与钥匙,但线程运行资源时,第一步时将资源锁住,由于其他线程的钥匙都打不开该线程的锁。那么其他的线程就会等待资源解锁的时候,而这时就只有该线程一个运行资源。但该线程运行完后,便会解锁,释放资源给其余的线程。周而复始,直到结束。

知道了线程同步的原理后,如何实现线程同步呢,有以下的方法:

1.使用synchronized同步代码块或者synchronized同步方法

将上述代码使用synchronized进行线程同步

/**
 * 同步线程
 * */
class SynThread implements Runnable{
    int n = 100;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<50;i++){
            synchronized(this){             //将资源锁住,只有正确的锁才能开锁,这里的锁用的是对象
                if(n<=0){
                    Thread.currentThread().stop();
                }
                System.out.print(Thread.currentThread() +" "+ i);
                System.out.print("\t"+Thread.currentThread().getPriority());
                System.out.print("\t当前n为:"+n);
                n--;
                System.out.println("\t售后n为"+n);
            }
        }
    }
}
public class Threads{
    public static void main(String[] args){
        SynThread ft = new SynThread();
        for(int i=0 ;i<4;i++){
            Thread t = new Thread(ft);
            t.start();
        }
        }
}        

运行结果如下:

Thread[Thread-0,5,main] 0    5    当前n为:100    售后n为99
Thread[Thread-0,5,main] 1    5    当前n为:99    售后n为98
Thread[Thread-0,5,main] 2    5    当前n为:98    售后n为97
Thread[Thread-0,5,main] 3    5    当前n为:97    售后n为96
Thread[Thread-2,5,main] 0    5    当前n为:96    售后n为95
Thread[Thread-2,5,main] 1    5    当前n为:95    售后n为94
Thread[Thread-2,5,main] 2    5    当前n为:94    售后n为93
Thread[Thread-2,5,main] 3    5    当前n为:93    售后n为92
Thread[Thread-2,5,main] 4    5    当前n为:92    售后n为91
Thread[Thread-2,5,main] 5    5    当前n为:91    售后n为90
Thread[Thread-2,5,main] 6    5    当前n为:90    售后n为89
Thread[Thread-2,5,main] 7    5    当前n为:89    售后n为88
Thread[Thread-2,5,main] 8    5    当前n为:88    售后n为87
Thread[Thread-2,5,main] 9    5    当前n为:87    售后n为86
Thread[Thread-2,5,main] 10    5    当前n为:86    售后n为85
Thread[Thread-2,5,main] 11    5    当前n为:85    售后n为84
Thread[Thread-2,5,main] 12    5    当前n为:84    售后n为83
Thread[Thread-2,5,main] 13    5    当前n为:83    售后n为82
Thread[Thread-2,5,main] 14    5    当前n为:82    售后n为81
Thread[Thread-2,5,main] 15    5    当前n为:81    售后n为80
Thread[Thread-2,5,main] 16    5    当前n为:80    售后n为79
Thread[Thread-2,5,main] 17    5    当前n为:79    售后n为78
Thread[Thread-2,5,main] 18    5    当前n为:78    售后n为77
Thread[Thread-2,5,main] 19    5    当前n为:77    售后n为76
Thread[Thread-2,5,main] 20    5    当前n为:76    售后n为75
Thread[Thread-2,5,main] 21    5    当前n为:75    售后n为74
Thread[Thread-2,5,main] 22    5    当前n为:74    售后n为73
Thread[Thread-2,5,main] 23    5    当前n为:73    售后n为72
Thread[Thread-2,5,main] 24    5    当前n为:72    售后n为71
Thread[Thread-2,5,main] 25    5    当前n为:71    售后n为70
Thread[Thread-2,5,main] 26    5    当前n为:70    售后n为69
Thread[Thread-2,5,main] 27    5    当前n为:69    售后n为68
Thread[Thread-2,5,main] 28    5    当前n为:68    售后n为67
Thread[Thread-2,5,main] 29    5    当前n为:67    售后n为66
Thread[Thread-2,5,main] 30    5    当前n为:66    售后n为65
Thread[Thread-2,5,main] 31    5    当前n为:65    售后n为64
Thread[Thread-2,5,main] 32    5    当前n为:64    售后n为63
Thread[Thread-2,5,main] 33    5    当前n为:63    售后n为62
Thread[Thread-2,5,main] 34    5    当前n为:62    售后n为61
Thread[Thread-2,5,main] 35    5    当前n为:61    售后n为60
Thread[Thread-2,5,main] 36    5    当前n为:60    售后n为59
Thread[Thread-2,5,main] 37    5    当前n为:59    售后n为58
Thread[Thread-2,5,main] 38    5    当前n为:58    售后n为57
Thread[Thread-2,5,main] 39    5    当前n为:57    售后n为56
Thread[Thread-2,5,main] 40    5    当前n为:56    售后n为55
Thread[Thread-2,5,main] 41    5    当前n为:55    售后n为54
Thread[Thread-2,5,main] 42    5    当前n为:54    售后n为53
Thread[Thread-2,5,main] 43    5    当前n为:53    售后n为52
Thread[Thread-2,5,main] 44    5    当前n为:52    售后n为51
Thread[Thread-2,5,main] 45    5    当前n为:51    售后n为50
Thread[Thread-2,5,main] 46    5    当前n为:50    售后n为49
Thread[Thread-2,5,main] 47    5    当前n为:49    售后n为48
Thread[Thread-2,5,main] 48    5    当前n为:48    售后n为47
Thread[Thread-2,5,main] 49    5    当前n为:47    售后n为46
Thread[Thread-3,5,main] 0    5    当前n为:46    售后n为45
Thread[Thread-3,5,main] 1    5    当前n为:45    售后n为44
Thread[Thread-3,5,main] 2    5    当前n为:44    售后n为43
Thread[Thread-3,5,main] 3    5    当前n为:43    售后n为42
Thread[Thread-3,5,main] 4    5    当前n为:42    售后n为41
Thread[Thread-3,5,main] 5    5    当前n为:41    售后n为40
Thread[Thread-3,5,main] 6    5    当前n为:40    售后n为39
Thread[Thread-3,5,main] 7    5    当前n为:39    售后n为38
Thread[Thread-3,5,main] 8    5    当前n为:38    售后n为37
Thread[Thread-3,5,main] 9    5    当前n为:37    售后n为36
Thread[Thread-3,5,main] 10    5    当前n为:36    售后n为35
Thread[Thread-3,5,main] 11    5    当前n为:35    售后n为34
Thread[Thread-3,5,main] 12    5    当前n为:34    售后n为33
Thread[Thread-3,5,main] 13    5    当前n为:33    售后n为32
Thread[Thread-3,5,main] 14    5    当前n为:32    售后n为31
Thread[Thread-3,5,main] 15    5    当前n为:31    售后n为30
Thread[Thread-3,5,main] 16    5    当前n为:30    售后n为29
Thread[Thread-3,5,main] 17    5    当前n为:29    售后n为28
Thread[Thread-3,5,main] 18    5    当前n为:28    售后n为27
Thread[Thread-3,5,main] 19    5    当前n为:27    售后n为26
Thread[Thread-3,5,main] 20    5    当前n为:26    售后n为25
Thread[Thread-3,5,main] 21    5    当前n为:25    售后n为24
Thread[Thread-3,5,main] 22    5    当前n为:24    售后n为23
Thread[Thread-3,5,main] 23    5    当前n为:23    售后n为22
Thread[Thread-3,5,main] 24    5    当前n为:22    售后n为21
Thread[Thread-3,5,main] 25    5    当前n为:21    售后n为20
Thread[Thread-3,5,main] 26    5    当前n为:20    售后n为19
Thread[Thread-3,5,main] 27    5    当前n为:19    售后n为18
Thread[Thread-3,5,main] 28    5    当前n为:18    售后n为17
Thread[Thread-3,5,main] 29    5    当前n为:17    售后n为16
Thread[Thread-3,5,main] 30    5    当前n为:16    售后n为15
Thread[Thread-3,5,main] 31    5    当前n为:15    售后n为14
Thread[Thread-3,5,main] 32    5    当前n为:14    售后n为13
Thread[Thread-3,5,main] 33    5    当前n为:13    售后n为12
Thread[Thread-3,5,main] 34    5    当前n为:12    售后n为11
Thread[Thread-3,5,main] 35    5    当前n为:11    售后n为10
Thread[Thread-3,5,main] 36    5    当前n为:10    售后n为9
Thread[Thread-1,5,main] 0    5    当前n为:9    售后n为8
Thread[Thread-1,5,main] 1    5    当前n为:8    售后n为7
Thread[Thread-1,5,main] 2    5    当前n为:7    售后n为6
Thread[Thread-1,5,main] 3    5    当前n为:6    售后n为5
Thread[Thread-1,5,main] 4    5    当前n为:5    售后n为4
Thread[Thread-1,5,main] 5    5    当前n为:4    售后n为3
Thread[Thread-1,5,main] 6    5    当前n为:3    售后n为2
Thread[Thread-1,5,main] 7    5    当前n为:2    售后n为1
Thread[Thread-1,5,main] 8    5    当前n为:1    售后n为0

  2. 使用lock锁进行同步

/**
 * lock同步锁
 * */
class LockThread implements Runnable{
    LockTest lockTest = null;
    public LockThread(LockTest lockTest){
        this.lockTest = lockTest;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<100;i++){
            lockTest.sub();
        }
    }
}

class LockTest{
    int n = 100;
    private final ReentrantLock lock = new ReentrantLock();

    public void sub(){
        lock.lock();
        try{
            if(n>0){
                System.out.print(Thread.currentThread()+"操作");
                System.out.print("\t当前n数为:"+n);
                n--;
                System.out.println("\t 操作后n数为:"+n);
            }else{
                System.out.println(Thread.currentThread()+"结束");
                Thread.currentThread().stop();
            }
        }finally{
            lock.unlock();
        }
    }
}
public class Threads{
    public static void main(String[] args){
        LockTest lockTest = new LockTest();
        LockThread lockThread = new LockThread(lockTest);
        for(int i=0 ;i<4;i++){
            Thread s = new Thread(lockThread);
            s.start();
        }
    }
}

运行结果如下:

Thread[Thread-0,5,main]操作    当前n数为:100     操作后n数为:99
Thread[Thread-0,5,main]操作    当前n数为:99     操作后n数为:98
Thread[Thread-0,5,main]操作    当前n数为:98     操作后n数为:97
Thread[Thread-0,5,main]操作    当前n数为:97     操作后n数为:96
Thread[Thread-1,5,main]操作    当前n数为:96     操作后n数为:95
Thread[Thread-1,5,main]操作    当前n数为:95     操作后n数为:94
Thread[Thread-1,5,main]操作    当前n数为:94     操作后n数为:93
Thread[Thread-1,5,main]操作    当前n数为:93     操作后n数为:92
Thread[Thread-1,5,main]操作    当前n数为:92     操作后n数为:91
Thread[Thread-1,5,main]操作    当前n数为:91     操作后n数为:90
Thread[Thread-1,5,main]操作    当前n数为:90     操作后n数为:89
Thread[Thread-1,5,main]操作    当前n数为:89     操作后n数为:88
Thread[Thread-1,5,main]操作    当前n数为:88     操作后n数为:87
Thread[Thread-1,5,main]操作    当前n数为:87     操作后n数为:86
Thread[Thread-1,5,main]操作    当前n数为:86     操作后n数为:85
Thread[Thread-1,5,main]操作    当前n数为:85     操作后n数为:84
Thread[Thread-1,5,main]操作    当前n数为:84     操作后n数为:83
Thread[Thread-1,5,main]操作    当前n数为:83     操作后n数为:82
Thread[Thread-1,5,main]操作    当前n数为:82     操作后n数为:81
Thread[Thread-1,5,main]操作    当前n数为:81     操作后n数为:80
Thread[Thread-1,5,main]操作    当前n数为:80     操作后n数为:79
Thread[Thread-1,5,main]操作    当前n数为:79     操作后n数为:78
Thread[Thread-1,5,main]操作    当前n数为:78     操作后n数为:77
Thread[Thread-1,5,main]操作    当前n数为:77     操作后n数为:76
Thread[Thread-1,5,main]操作    当前n数为:76     操作后n数为:75
Thread[Thread-1,5,main]操作    当前n数为:75     操作后n数为:74
Thread[Thread-1,5,main]操作    当前n数为:74     操作后n数为:73
Thread[Thread-1,5,main]操作    当前n数为:73     操作后n数为:72
Thread[Thread-1,5,main]操作    当前n数为:72     操作后n数为:71
Thread[Thread-1,5,main]操作    当前n数为:71     操作后n数为:70
Thread[Thread-1,5,main]操作    当前n数为:70     操作后n数为:69
Thread[Thread-1,5,main]操作    当前n数为:69     操作后n数为:68
Thread[Thread-1,5,main]操作    当前n数为:68     操作后n数为:67
Thread[Thread-1,5,main]操作    当前n数为:67     操作后n数为:66
Thread[Thread-1,5,main]操作    当前n数为:66     操作后n数为:65
Thread[Thread-1,5,main]操作    当前n数为:65     操作后n数为:64
Thread[Thread-1,5,main]操作    当前n数为:64     操作后n数为:63
Thread[Thread-1,5,main]操作    当前n数为:63     操作后n数为:62
Thread[Thread-1,5,main]操作    当前n数为:62     操作后n数为:61
Thread[Thread-1,5,main]操作    当前n数为:61     操作后n数为:60
Thread[Thread-1,5,main]操作    当前n数为:60     操作后n数为:59
Thread[Thread-1,5,main]操作    当前n数为:59     操作后n数为:58
Thread[Thread-1,5,main]操作    当前n数为:58     操作后n数为:57
Thread[Thread-1,5,main]操作    当前n数为:57     操作后n数为:56
Thread[Thread-1,5,main]操作    当前n数为:56     操作后n数为:55
Thread[Thread-1,5,main]操作    当前n数为:55     操作后n数为:54
Thread[Thread-1,5,main]操作    当前n数为:54     操作后n数为:53
Thread[Thread-1,5,main]操作    当前n数为:53     操作后n数为:52
Thread[Thread-1,5,main]操作    当前n数为:52     操作后n数为:51
Thread[Thread-1,5,main]操作    当前n数为:51     操作后n数为:50
Thread[Thread-1,5,main]操作    当前n数为:50     操作后n数为:49
Thread[Thread-1,5,main]操作    当前n数为:49     操作后n数为:48
Thread[Thread-1,5,main]操作    当前n数为:48     操作后n数为:47
Thread[Thread-1,5,main]操作    当前n数为:47     操作后n数为:46
Thread[Thread-1,5,main]操作    当前n数为:46     操作后n数为:45
Thread[Thread-1,5,main]操作    当前n数为:45     操作后n数为:44
Thread[Thread-1,5,main]操作    当前n数为:44     操作后n数为:43
Thread[Thread-1,5,main]操作    当前n数为:43     操作后n数为:42
Thread[Thread-1,5,main]操作    当前n数为:42     操作后n数为:41
Thread[Thread-1,5,main]操作    当前n数为:41     操作后n数为:40
Thread[Thread-1,5,main]操作    当前n数为:40     操作后n数为:39
Thread[Thread-1,5,main]操作    当前n数为:39     操作后n数为:38
Thread[Thread-1,5,main]操作    当前n数为:38     操作后n数为:37
Thread[Thread-1,5,main]操作    当前n数为:37     操作后n数为:36
Thread[Thread-1,5,main]操作    当前n数为:36     操作后n数为:35
Thread[Thread-1,5,main]操作    当前n数为:35     操作后n数为:34
Thread[Thread-1,5,main]操作    当前n数为:34     操作后n数为:33
Thread[Thread-1,5,main]操作    当前n数为:33     操作后n数为:32
Thread[Thread-1,5,main]操作    当前n数为:32     操作后n数为:31
Thread[Thread-1,5,main]操作    当前n数为:31     操作后n数为:30
Thread[Thread-1,5,main]操作    当前n数为:30     操作后n数为:29
Thread[Thread-1,5,main]操作    当前n数为:29     操作后n数为:28
Thread[Thread-1,5,main]操作    当前n数为:28     操作后n数为:27
Thread[Thread-1,5,main]操作    当前n数为:27     操作后n数为:26
Thread[Thread-1,5,main]操作    当前n数为:26     操作后n数为:25
Thread[Thread-1,5,main]操作    当前n数为:25     操作后n数为:24
Thread[Thread-1,5,main]操作    当前n数为:24     操作后n数为:23
Thread[Thread-1,5,main]操作    当前n数为:23     操作后n数为:22
Thread[Thread-1,5,main]操作    当前n数为:22     操作后n数为:21
Thread[Thread-1,5,main]操作    当前n数为:21     操作后n数为:20
Thread[Thread-1,5,main]操作    当前n数为:20     操作后n数为:19
Thread[Thread-1,5,main]操作    当前n数为:19     操作后n数为:18
Thread[Thread-1,5,main]操作    当前n数为:18     操作后n数为:17
Thread[Thread-1,5,main]操作    当前n数为:17     操作后n数为:16
Thread[Thread-1,5,main]操作    当前n数为:16     操作后n数为:15
Thread[Thread-1,5,main]操作    当前n数为:15     操作后n数为:14
Thread[Thread-1,5,main]操作    当前n数为:14     操作后n数为:13
Thread[Thread-1,5,main]操作    当前n数为:13     操作后n数为:12
Thread[Thread-1,5,main]操作    当前n数为:12     操作后n数为:11
Thread[Thread-1,5,main]操作    当前n数为:11     操作后n数为:10
Thread[Thread-1,5,main]操作    当前n数为:10     操作后n数为:9
Thread[Thread-1,5,main]操作    当前n数为:9     操作后n数为:8
Thread[Thread-1,5,main]操作    当前n数为:8     操作后n数为:7
Thread[Thread-1,5,main]操作    当前n数为:7     操作后n数为:6
Thread[Thread-1,5,main]操作    当前n数为:6     操作后n数为:5
Thread[Thread-1,5,main]操作    当前n数为:5     操作后n数为:4
Thread[Thread-1,5,main]操作    当前n数为:4     操作后n数为:3
Thread[Thread-1,5,main]操作    当前n数为:3     操作后n数为:2
Thread[Thread-1,5,main]操作    当前n数为:2     操作后n数为:1
Thread[Thread-1,5,main]操作    当前n数为:1     操作后n数为:0
Thread[Thread-1,5,main]结束
Thread[Thread-2,5,main]结束
Thread[Thread-3,5,main]结束
Thread[Thread-0,5,main]结束

无论是使用方法一或者方法二,从运行的结果可以发现,结果都是有序运行的,而不想未同步时的顺序打乱。有关线程同步有以下需要注意的地方:

1. 实现线程同步的前提条件是多线程,并且线程执行内容要一致(引用同一线程targer对象)。若是单一线程,根本无需用到锁。

2. 同步的资源不一定放在run方法中,也可以放在其他的方法体里,让run方法调用该方法。

3. 线程同步,有可能会造成死锁,何为死锁,线程1需要线程2的锁放可进行运行,而线程2需要线程1的锁放可运行。两个线程都不让步,便会造成死锁。在程序中,由于资源被锁住的原因,线程进入阻塞状态,并且双方都不让步,便会导致了两个线程无限的等待下去。因此编写程序时应该避免死锁。

线程通信:

当两个线程执行的内容不同,但相互间有联系,这便是线程的通信。要先实现线程通信,有以下的条件:

1. 必须有两个或以上不同的线程执行体,即run方法执行的内容不一致

2. 每个线程执行体必须符合线程同步。

线程通信最经典的例子便是生产者与消费者。生产者生产一件东西,而消费者消费东西。其执行顺序时,生产1,消费1,生产2,消费2的顺序。由于生产者与消费者不仅仅只是单一线程的生产与消费,因此生产者与消费者需要当作资源锁住。如何实现线程通信,有以下的方法:

1.使用synchronized与Object.wait(),notify(),notifyAll()方法实现

2.使用lock同步锁与Condition类实现

3.使用阻塞队列BlockingQueue实现

以下是代码:

建立一个生产者与消费者都会使用到的类Request

class Requests{
    private final Lock lock = new ReentrantLock();
    private final Condition cond = lock.newCondition();
    //创建长度为2的阻塞队列
    private final BlockingQueue aQueue = new ArrayBlockingQueue(2);
    String url;
    int paramentCount;
    boolean bFull,lFull = false;

    /**
     * 使用synchronized同步块或同步方法进行通讯
     * */
    public synchronized void set_1(String url,int paramentCount){
        if(bFull){
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        this.url = url;
        this.paramentCount = paramentCount;
        System.out.println("synchronized "+Thread.currentThread()+" 放入了"+url+"----->"+paramentCount);
        bFull = true;
        notify();
    }
    public synchronized void get_1(){
        if(!bFull){
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println("synchronized"+Thread.currentThread()+url+"------->"+paramentCount);
        bFull = false;
        notify();
    }

    /**
     * 使用lock同步锁进行通讯
     * */
    public void set_2(String url,int paramentCount){
        lock.lock();
        try{
            if(lFull){
                try {
                    cond.await();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            this.url = url;
            this.paramentCount = paramentCount;
            System.out.println("lock  "+Thread.currentThread()+" 放入了"+url+"----->"+paramentCount);
            lFull = true;
            cond.signal();
        }finally{
            lock.unlock();
        }
    }
    public void get_2(){
        lock.lock();
        try{
            if(!lFull){
                try {
                    cond.await();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println("lock  "+Thread.currentThread()+"取出来"+url+"------->"+paramentCount);
            lFull = false;
            cond.signal();
        }finally{
            lock.unlock();
        }
    }

    /**
     * 使用BlockingQueue进行通讯
     * */
    public void set_3(String url,int paramentCount){
        try {
            aQueue.put(url+"  "+paramentCount);
            System.out.println("lock  "+Thread.currentThread()+" 放入了数据");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public void get_3(){
        try {
            System.out.println("BlockingQueue  "+Thread.currentThread()+"取出来数据:"+aQueue.take());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

在Request中一个有6个方法,set_1,set_2,set_3,get_1,get_2,get3方法。其中,set_1与get_1使用的是的synchronized与Object.wait(),notify(),notifyAll()方法得线程通信,set_2与get_2是使用lock同步锁与Condition类实现的线程通信,set_3与get_3则是使用阻塞队列BlockingQueue实现的线程通信。

生产者类:

class Productor implements Runnable{
    Requests request = null;
    public Productor(Requests requests){
        request = requests;
        Thread t = new Thread(this);
        t.start();
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<10;i++){
            if(i%2 == 0){
                //使用Synchronized同步块或者同步方法
//                request.set_1("localhost", 1);
                //使用lock同步锁
//                request.set_2("localhost", 1);
                //使用BlockingQueue阻塞队列
                request.set_3("localhost", 1);
            }else{
                //使用Synchronized同步块或者同步方法
//                request.set_1("127.0.0.1", 3);
//                使用lock同步锁
//                request.set_2("127.0.0.1", 3);
                //使用BlockingQueue阻塞队列
                request.set_3("127.0.0.1", 3);
            }
        }
    }
}

消费者:

class Consumer implements Runnable{
    Requests request = null;
    public Consumer(Requests requests){
        request = requests;
        Thread t = new Thread(this);
        t.start();
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<10;i++){
            //使用Synchronized同步块或者同步方法
//            request.get_1();
            //使用lock同步锁
//            request.get_2();
            //使用BlockingQueue阻塞队列
            request.get_3();
        }
    }
}

使用生产者与消费者创建线程并运行:

public class Threads{
    public static void main(String[] args){
        Requests request = new Requests();
        Productor p = new Productor(request);
        Consumer c = new Consumer(request);
        }
}        

由于生产者与消费者都有三种实现线程通信的方法,需要注释另外两种,仅有一种线程通信方法运行结果如下:

方法一运行效果如下:

synchronized Thread[Thread-0,5,main] 放入了localhost----->1
synchronizedThread[Thread-1,5,main]localhost------->1
synchronized Thread[Thread-0,5,main] 放入了127.0.0.1----->3
synchronizedThread[Thread-1,5,main]127.0.0.1------->3
synchronized Thread[Thread-0,5,main] 放入了localhost----->1
synchronizedThread[Thread-1,5,main]localhost------->1
synchronized Thread[Thread-0,5,main] 放入了127.0.0.1----->3
synchronizedThread[Thread-1,5,main]127.0.0.1------->3
synchronized Thread[Thread-0,5,main] 放入了localhost----->1
synchronizedThread[Thread-1,5,main]localhost------->1
synchronized Thread[Thread-0,5,main] 放入了127.0.0.1----->3
synchronizedThread[Thread-1,5,main]127.0.0.1------->3
synchronized Thread[Thread-0,5,main] 放入了localhost----->1
synchronizedThread[Thread-1,5,main]localhost------->1
synchronized Thread[Thread-0,5,main] 放入了127.0.0.1----->3
synchronizedThread[Thread-1,5,main]127.0.0.1------->3
synchronized Thread[Thread-0,5,main] 放入了localhost----->1
synchronizedThread[Thread-1,5,main]localhost------->1
synchronized Thread[Thread-0,5,main] 放入了127.0.0.1----->3
synchronizedThread[Thread-1,5,main]127.0.0.1------->3

方法二运行效果如下:

lock  Thread[Thread-0,5,main] 放入了localhost----->1
lock  Thread[Thread-1,5,main]取出来localhost------->1
lock  Thread[Thread-0,5,main] 放入了127.0.0.1----->3
lock  Thread[Thread-1,5,main]取出来127.0.0.1------->3
lock  Thread[Thread-0,5,main] 放入了localhost----->1
lock  Thread[Thread-1,5,main]取出来localhost------->1
lock  Thread[Thread-0,5,main] 放入了127.0.0.1----->3
lock  Thread[Thread-1,5,main]取出来127.0.0.1------->3
lock  Thread[Thread-0,5,main] 放入了localhost----->1
lock  Thread[Thread-1,5,main]取出来localhost------->1
lock  Thread[Thread-0,5,main] 放入了127.0.0.1----->3
lock  Thread[Thread-1,5,main]取出来127.0.0.1------->3
lock  Thread[Thread-0,5,main] 放入了localhost----->1
lock  Thread[Thread-1,5,main]取出来localhost------->1
lock  Thread[Thread-0,5,main] 放入了127.0.0.1----->3
lock  Thread[Thread-1,5,main]取出来127.0.0.1------->3
lock  Thread[Thread-0,5,main] 放入了localhost----->1
lock  Thread[Thread-1,5,main]取出来localhost------->1
lock  Thread[Thread-0,5,main] 放入了127.0.0.1----->3
lock  Thread[Thread-1,5,main]取出来127.0.0.1------->3

方法三运行效果如下:

BlockingQueue  Thread[Thread-0,5,main] 放入了数据
BlockingQueue  Thread[Thread-0,5,main] 放入了数据
BlockingQueue  Thread[Thread-1,5,main]取出来数据:localhost  1
BlockingQueue  Thread[Thread-1,5,main]取出来数据:127.0.0.1  3
BlockingQueue  Thread[Thread-0,5,main] 放入了数据
BlockingQueue  Thread[Thread-1,5,main]取出来数据:localhost  1
BlockingQueue  Thread[Thread-0,5,main] 放入了数据
BlockingQueue  Thread[Thread-1,5,main]取出来数据:127.0.0.1  3
BlockingQueue  Thread[Thread-0,5,main] 放入了数据
BlockingQueue  Thread[Thread-1,5,main]取出来数据:localhost  1
BlockingQueue  Thread[Thread-0,5,main] 放入了数据
BlockingQueue  Thread[Thread-1,5,main]取出来数据:127.0.0.1  3
BlockingQueue  Thread[Thread-0,5,main] 放入了数据
BlockingQueue  Thread[Thread-0,5,main] 放入了数据
BlockingQueue  Thread[Thread-0,5,main] 放入了数据
BlockingQueue  Thread[Thread-1,5,main]取出来数据:localhost  1
BlockingQueue  Thread[Thread-1,5,main]取出来数据:127.0.0.1  3
BlockingQueue  Thread[Thread-0,5,main] 放入了数据
BlockingQueue  Thread[Thread-1,5,main]取出来数据:localhost  1
BlockingQueue  Thread[Thread-1,5,main]取出来数据:127.0.0.1  3

由于方法三实现的通信原理与方法一和方法二不同,因此不能像方法一与方法二那样一生产一消费,但也保证了消费前要生产。

全部代码:

class TestThread implements Runnable{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread()+" "+i);
        }
    }
}

/**
 * 未同步线程
 * */
class TestThreads implements Runnable{
    int n = 100;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<50;i++){
            System.out.print(Thread.currentThread() +" "+ i);
            System.out.print("\t"+Thread.currentThread().getPriority());
            System.out.print("\t当前n为:"+n);
            n--;
            System.out.println("\t售后n为"+n);
        }
    }
}

/**
 * 同步线程
 * */
class SynThread implements Runnable{
    int n = 100;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<50;i++){
            synchronized(this){
                if(n<=0){
                    Thread.currentThread().stop();
                }
                System.out.print(Thread.currentThread() +" "+ i);
                System.out.print("\t"+Thread.currentThread().getPriority());
                System.out.print("\t当前n为:"+n);
                n--;
                System.out.println("\t售后n为"+n);
            }
        }
    }
}

/**
 * lock同步锁
 * */
class LockThread implements Runnable{
    LockTest lockTest = null;
    public LockThread(LockTest lockTest){
        this.lockTest = lockTest;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<100;i++){
            lockTest.sub();
        }
    }
}

class LockTest{
    int n = 100;
    private final ReentrantLock lock = new ReentrantLock();

    public void sub(){
        lock.lock();
        try{
            if(n>0){
                System.out.print(Thread.currentThread()+"操作");
                System.out.print("\t当前n数为:"+n);
                n--;
                System.out.println("\t 操作后n数为:"+n);
            }else{
                System.out.println(Thread.currentThread()+"结束");
                Thread.currentThread().stop();
            }
        }finally{
            lock.unlock();
        }
    }
}

/**
 * 线程通讯
 * */
class Productor implements Runnable{
    Requests request = null;
    public Productor(Requests requests){
        request = requests;
        Thread t = new Thread(this);
        t.start();
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<10;i++){
            if(i%2 == 0){
                //使用Synchronized同步块或者同步方法
//                request.set_1("localhost", 1);
                //使用lock同步锁
//                request.set_2("localhost", 1);
                //使用BlockingQueue阻塞队列
                request.set_3("localhost", 1);
            }else{
                //使用Synchronized同步块或者同步方法
//                request.set_1("127.0.0.1", 3);
//                使用lock同步锁
//                request.set_2("127.0.0.1", 3);
                //使用BlockingQueue阻塞队列
                request.set_3("127.0.0.1", 3);
            }
        }
    }
}

class Consumer implements Runnable{
    Requests request = null;
    public Consumer(Requests requests){
        request = requests;
        Thread t = new Thread(this);
        t.start();
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i=0;i<10;i++){
            //使用Synchronized同步块或者同步方法
//            request.get_1();
            //使用lock同步锁
//            request.get_2();
            //使用BlockingQueue阻塞队列
            request.get_3();
        }
    }
}
class Requests{
    private final Lock lock = new ReentrantLock();
    private final Condition cond = lock.newCondition();
    //创建长度为2的阻塞队列
    private final BlockingQueue aQueue = new ArrayBlockingQueue(2);
    String url;
    int paramentCount;
    boolean bFull,lFull = false;

    /**
     * 使用synchronized同步块或同步方法进行通讯
     * */
    public synchronized void set_1(String url,int paramentCount){
        if(bFull){
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        this.url = url;
        this.paramentCount = paramentCount;
        System.out.println("synchronized "+Thread.currentThread()+" 放入了"+url+"----->"+paramentCount);
        bFull = true;
        notify();
    }
    public synchronized void get_1(){
        if(!bFull){
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        System.out.println("synchronized"+Thread.currentThread()+url+"------->"+paramentCount);
        bFull = false;
        notify();
    }

    /**
     * 使用lock同步锁进行通讯
     * */
    public void set_2(String url,int paramentCount){
        lock.lock();
        try{
            if(lFull){
                try {
                    cond.await();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            this.url = url;
            this.paramentCount = paramentCount;
            System.out.println("lock  "+Thread.currentThread()+" 放入了"+url+"----->"+paramentCount);
            lFull = true;
            cond.signal();
        }finally{
            lock.unlock();
        }
    }
    public void get_2(){
        lock.lock();
        try{
            if(!lFull){
                try {
                    cond.await();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println("lock  "+Thread.currentThread()+"取出来"+url+"------->"+paramentCount);
            lFull = false;
            cond.signal();
        }finally{
            lock.unlock();
        }
    }

    /**
     * 使用BlockingQueue进行通讯
     * */
    public void set_3(String url,int paramentCount){
        try {
            aQueue.put(url+"  "+paramentCount);
            System.out.println("BlockingQueue  "+Thread.currentThread()+" 放入了数据");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public void get_3(){
        try {
            System.out.println("BlockingQueue  "+Thread.currentThread()+"取出来数据:"+aQueue.take());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

public class Threads{
    public static void main(String[] args){
        /**
         * 线程控制1
         * */
//        TestThread testThread = new TestThread();
//        for(int i=0;i<5;i++){
//            Thread t = new Thread(testThread);
//            t.start();
//        }

        /**
         * 线程优先级设置
         * */
//        TestThread testThread = new TestThread();
//        Thread t_1 = new Thread(testThread);
//        Thread t_2 = new Thread(testThread);
//        Thread t_3 = new Thread(testThread);
//        Thread t_4 = new Thread(testThread);
//        Thread t_5 = new Thread(testThread);
//        t_5.setPriority(10);
//        t_5.start();t_1.start();t_2.start();t_3.start();t_4.start();

//        /**
//         * 线程停止运行的方法
//         * */
//        System.out.println(Thread.currentThread()+"开始运行");
//        TestThread test = new TestThread();
//        Thread t_1 = new Thread(test);
//        Thread t_2 = new Thread(test);
//        Thread t_3 = new Thread(test);
//        try{
//            t_1.start();t_2.start();t_3.start();
//            t_1.join();
//        }catch(Exception e){}
//        System.out.println(Thread.currentThread()+"停止运行");

        /**
         * 未同步线程
         * */
//        TestThreads testThreads = new TestThreads();
//        Thread t_1 = new Thread(testThreads);
//        Thread t_2 = new Thread(testThreads);
//        Thread t_3 = new Thread(testThreads);
//        t_1.start();t_2.start();t_3.start();

       /**
        * 同步的条件:引用同个target线程对象
        * */
//        SynThread ft = new SynThread();
//        LockTest lockTest = new LockTest();
//        LockThread lockThread = new LockThread(lockTest);
//        for(int i=0 ;i<4;i++){
////            Thread t = new Thread(ft);
////            t.start();
//            Thread s = new Thread(lockThread);
//            s.start();
//        }

        /**
         * 线程通讯
         * 要实现线程通讯(两个不同对象不同run方法的线程)
         * 1. 同步资源
         * 2. 当一个线程获取时,另外的线程停止。
         * */
        Requests request = new Requests();
        Productor p = new Productor(request);
        Consumer c = new Consumer(request);
    }
}

原文地址:https://www.cnblogs.com/hjlin/p/11394264.html

时间: 2024-10-11 09:07:30

Java 线程(多线程)详解的相关文章

Java线程池详解(二)

一.前言 在总结了线程池的一些原理及实现细节之后,产出了一篇文章:Java线程池详解(一),后面的(一)是在本文出现之后加上的,而本文就成了(二).因为在写完第一篇关于java线程池的文章之后,越发觉得还有太多内容需要补充,每次都是修修补补,总觉得还缺点什么.在第一篇中,我着重描述了java线程池的原理以及它的实现,主要的点在于它是如何工作的.而本文的内容将更为上层,重点在于如何应用java线程池,算是对第一篇文章的一点补充,这样对于java线程池的学习和总结稍微完整一些. 使用过java线程池

java线程池详解一

1.为什么要用线程池技术 诸如Web服务器.数据库服务器.文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务.请求以某种方式到达服务器,这种方式可能是通过网络协议(例如 HTTP.FTP 或 POP).通过 JMS 队列或者可能通过轮询数据库.不管请求如何到达,服务器应用程序中经常出现的情况是:单个任务处理的时间很短而请求的数目却是巨大的. 构建服务器应用程序的一个过于简单的模型应该是:每当一个请求到达就创建一个新线程,然后在新线程中为请求服务.实际上,对于

【java线程系列】java线程系列之java线程池详解

一线程池的概念及为何需要线程池: 我们知道当我们自己创建一个线程时如果该线程执行完任务后就进入死亡状态,这样如果我们需要在次使用一个线程时得重新创建一个线程,但是线程的创建是要付出一定的代价的,如果在我们的程序中需要频繁使用线程,且每个线程执行的时间很短,短到几乎小于线程创建及销毁的时间那么代价将会更大,如:服务器应用程序中经常出现的情况是:单个任务处理的时间很短而请求的数目却是巨大的.显然如果频繁的创建销毁线程效率将非常低. 那么我们能否让一个线程可以复用,即当一个线程执行完后不销毁该线程,而

Java线程池 详解(图解)

来源:www.jianshu.com/p/098819be088c 前言   Java中的线程池十分重要,无论是在实际应用中还是应对面试 一.线程池原理 1.1 使用线程池的好处 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 第三:提高线程的可管理性.线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配.调优和监控. 1.2 线程池的实现原理

Java线程常用方法详解

线程的常用方法 1.start() : 线程调用该方法将启动线程,使之从新建状态进入就绪队列排队,一旦轮到它来享用CPU资源时,就可以脱离创建它的线程独立开始自己的生命周期了. 2.run(): Thread类的run()方法与Runnable接口中的run()方法的功能和作用相同,都用来定义线程对象被调度之后所执行的操作,都是系统自动调用而用户程序不得引用的方法. 3.sleep(int millsecond): 优先级高的线程可以在它的run()方法中调用sleep方法来使自己放弃CPU资源

Java线程池详解及实例

前言 多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担.线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致Out of Memory.即便没有这样的情况,大量的线程回收也会给GC带来很大的压力. 为了避免重复的创建线程,线程池的出现可以让线程进行复用.通俗点讲,当有工作来,就会向线程池拿一个线程,当工作完成后,并不是直接关闭线程,而是将这个线程归还给线程池供其他任务使用. 接下来从总体到细致的方式,来共同探讨线程池. 总体的架构

Java线程池详解

一.线程池初探 所谓线程池,就是将多个线程放在一个池子里面(所谓池化技术),然后需要线程的时候不是创建一个线程,而是从线程池里面获取一个可用的线程,然后执行我们的任务.线程池的关键在于它为我们管理了多个线程,我们不需要关心如何创建线程,我们只需要关系我们的核心业务,然后需要线程来执行任务的时候从线程 http://pic.cnhubei.com/space.php?uid=1913&do=album&id=1109585http://pic.cnhubei.com/space.php?ui

关于Java线程池详解(二)

一.为什么要用线程池? 1.减少资源的开销 : 2.减少了每次创建线程.销毁线程的开销: 3.提高响应速度 ,每次请求到来时,由于线程的创建已经完成,故可以直接执行任务,因此提高了响应速度. 提高线程的可管理性 ,线程是一种稀缺资源,若不加以限制,不仅会占用大量资源,而且会影响系统的稳定性. 因此,线程池可以对线程的创建与停止.线程数量等等因素加以控制,使得线程在一种可控的范围内运行,不仅能保证系统稳定运行,而且方便性能调优. 二.Executor框架中的所有类可以分成三类: 1.任务: 任务有

Java 多线程详解(二)------如何创建进程和线程

Java 多线程详解(一)------概念的引入:http://www.cnblogs.com/ysocean/p/6882988.html 在上一篇博客中,我们已经介绍了并发和并行的区别,以及进程和线程的理解,那么在Java 中如何创建进程和线程呢? 1.在 Windows 操作系统中创建进程 在 windows 操作系统中,我们创建一个进程通常就是打开某个应用软件,这便在电脑中创建了一个进程.更原始一点的,我们在命令提示符中来做(我们以打开记事本这个进程为例): 第一步:windows+R,