• 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("	"+Thread.currentThread().getPriority());
                System.out.print("	当前n为:"+n);
                n--;
                System.out.println("	售后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("	"+Thread.currentThread().getPriority());
                    System.out.print("	当前n为:"+n);
                    n--;
                    System.out.println("	售后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
    View Code

         

      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("	当前n数为:"+n);
                    n--;
                    System.out.println("	 操作后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]结束
    View Code

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

    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
    View Code

    方法二运行效果如下:

    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
    View Code

    方法三运行效果如下:

    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
    View Code

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

    全部代码:

    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("	"+Thread.currentThread().getPriority());
                System.out.print("	当前n为:"+n);
                n--;
                System.out.println("	售后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("	"+Thread.currentThread().getPriority());
                    System.out.print("	当前n为:"+n);
                    n--;
                    System.out.println("	售后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("	当前n数为:"+n);
                    n--;
                    System.out.println("	 操作后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);
        }
    }
    View Code
  • 相关阅读:
    Cesium案例解析(二)——ImageryLayers影像图层
    Cesium案例解析(一)——HelloWorld
    WebGL简易教程(十四):阴影
    WebGL简易教程(十三):帧缓存对象(离屏渲染)
    关于GDAL读写Shp乱码的问题总结
    WebGL简易教程(十二):包围球与投影
    GDAL集成对KML文件的支持
    WebGL简易教程(十一):纹理
    WebGL简易教程(十):光照
    WebGL简易教程(九):综合实例:地形的绘制
  • 原文地址:https://www.cnblogs.com/hjlin/p/11394264.html
Copyright © 2020-2023  润新知