zoukankan      html  css  js  c++  java
  • 多线程

       进程  

       是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序就是一个执行路径或者叫一个控制单元。

       线程

       就是进程中的一个独立的控制单元。线程在控制着进程的执行。

       一个进程中至少有一个线程。

       Java VM启动时会有一个进程java.exe,该进程中至少有一个线程负责java程序的执行。而且这个线程运行的代码存在main方法中,该线程称之为主线程

       扩展知识:其实更细节说明JVM,JVM不止启动一个线程,还有负责垃圾回收机制的线程

       如何在自定义的代码中,自定义定义一个线程?

       通过对API的查找,java已经提供了对线程这类事物的描述,即Thread类。

       创建线程的第一种方式:继承Thread类。

       步骤:

    1. 继承Thread类
    2. 重写Thread类中的run()。目的:将自定义的代码存储在run(),让线程运行
    3. 调用线程的start()。该方法有2个作用:启动线程,调用run()

       如下代码:

    class Demo extends Thread {
        public void run() {
            for(int x = 0; x < 60; x++)
                System.out.println("demo run----"+x);
        }
    }
    public class ThreadDemo {
    
        public static void main(String[] args) {
            Demo d = new Demo();//创建好一个线程
    //      d.start();//开启线程,并执行该线程的run()
            d.run();//仅仅是对象的调用方法,而线程创建了,并没有被运行 
            
            for(int x = 0; x < 60; x++)
                System.out.println("hello world!---"+x);
            
    //      Thread t = new Thread();
    //      t.start();
        }
    
    }

       发现运行结果每一次都不同。

       因为多个线程都在获取CPU的执行权,CPU执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序在运行(多核除外)。CPU在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象地把多线程的运行形容为互相抢夺CPU的执行权,这就是多线程的一个特点:随机性。谁抢到谁执行,至于执行多长,CPU说了算。

       为什么要覆盖run()呢?

       Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run()。也就是说Thread类中的run()用于存储线程要运行的代码。

       练习:

       创建两个线程,和主线程交替执行。

       代码示例:

    class Test extends Thread {
    //  private String name;
        
        Test(String name) {
            super(name);
        }
        public void run() {
            for(int x = 0; x < 60; x++)
                System.out.println((Thread.currentThread()==this)+"..."+this.getName()+" run..."+x);
        }
    }
    public class ThreadTest {
    
        public static void main(String[] args) {
            Test t1 = new Test("one----");
            Test t2 = new Test("two++++");
            t1.start();
            t2.start();
            
            for(int x = 0; x < 60; x++)
                System.out.println("main run..."+x);
        }
    
    }

       原来线程都有自己默认的名称:Thread-编号,该编号从0开始。

       static Thread currentThread():获取当前线程对象

       getName():获取线程名称

       设置线程名称:setName()或者构造函数

       

       以此例引申出创建线程的第二种方式:

       需求:简单的卖票程序。多个窗口同时买票。

       代码如下:  

    /*
    class Ticket extends Thread {
        private int tick = 100;
        public void run() {
            while(true) {
                if(tick > 0)
                    System.out.println(Thread.currentThread().getName()+"sale: "+tick--);
            }
        }
    }
    */
    class Ticket implements Runnable {
        private int tick = 100;
        public void run() {
            while(true) {
                if(tick > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
    
                    }
                    System.out.println(Thread.currentThread().getName()+"sale: "+tick--);
                }
            }
        }
    }
    public class ThreadTest1 {
    
        public static void main(String[] args) {
            /*
            Ticket t1 = new Ticket();
            Ticket t2 = new Ticket();
            Ticket t3 = new Ticket();
            Ticket t4 = new Ticket();
            
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            */
            Ticket t = new Ticket();
            
            Thread t1 = new Thread(t);//创建一个线程
            Thread t2 = new Thread(t);//创建一个线程
            Thread t3 = new Thread(t);//创建一个线程
            Thread t4 = new Thread(t);//创建一个线程
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    
    }

       创建线程的第二种方式:实现Runnable接口。

       步骤:

    1. 定义类实现Runnable接口
    2. 覆盖Runnable接口中的run()。目的:将线程要运行的代码存放在该run()中
    3. 通过Thread类建立线程对象
    4. 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。为什么要将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数?——因为自定义的run()所属的对象是Runnable接口的子类对象,所以要让线程去运行指定对象的run(),就必须明确该run()所属的对象
    5. 调用Thread类的start()开启线程并调用Runnable接口子类的run方法

       实现方式和继承方式有什么区别呢?

    1. 实现方式好处:避免了单继承的局限性。在定义线程时,建议使用实现方式
    2. 继承Thread:线程代码存放Thread子类的run()中
    3. 实现Runnable:线程代码存放在接口的子类的run()中

       

       还是以简单的卖票程序为例:

       通过分析发现打印出0、-1、-2等错票,多线程的运行出现了安全问题。

       问题的原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致了共享数据的错误。

       解决办法:对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。

       java对于多线程的安全问题提供了专业的解决方式——就是同步代码块

       格式:

    synchronized(对象) {
        需要被同步的代码
    }

       对象如同,持有锁的线程可以在同步中执行。没有持有锁的线程即使获取CPU的执行权,也进不去,因为没有锁。

       火车上的卫生间---经典同步例子。

       同步的前提:

    1. 必须要有两个或者两个以上的线程
    2. 必须是多个线程使用同一个锁 

       必须保证同步中只有一个线程在运行

       同步的好处:解决了多线程的安全问题。

       同步的弊端:多个线程需要判断锁,较为消耗资源。

       示例代码如下:

    class Ticket implements Runnable {
        private int tick = 100;
        Object obj = new Object();
        synchronized
        public void run() {
            while(true) {
                synchronized (obj) {
                    if(tick > 0) {
                        //模拟多线程的运行出现的安全问题
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            
                        }
                        System.out.println(Thread.currentThread().getName()+"sale: "+tick--);
                    }
                }
            }
        }
    }
    
    public class ThreadDemo1 {
    
        public static void main(String[] args) {
            Ticket t = new Ticket();
            
            Thread t1 = new Thread(t);//创建一个线程
            Thread t2 = new Thread(t);//创建一个线程
            Thread t3 = new Thread(t);//创建一个线程
            Thread t4 = new Thread(t);//创建一个线程
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    
    } 

       

       同步函数

       以此例引申出同步函数:   

       需求:银行有一个金库,有两个储户,分别存300元,每次存100元,存3次。

       程序代码如下:

    class Bank {
        private int sum;
        Object obj = new Object();
        public void add(int n) {
            sum = sum + n;
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                
            }
            System.out.println("sum="+sum);
        }
    }
    class Cus implements Runnable {
        private Bank b = new Bank();
        public void run() {
            for(int x = 0; x < 3; x++) {
                b.add(100);
            }
        }
        
    }
    public class BankDemo {
    
        public static void main(String[] args) {
            Cus c = new Cus();
            Thread t1 = new Thread(c);
            Thread t2 = new Thread(c);
            t1.start();
            t2.start();
        }
    
    }

       目的:该程序是否有安全问题,如果有,如何解决?

       如何找到问题:

    1. 明确哪些代码是多线程运行代码
    2. 明确共享数据
    3. 明确多线程运行代码中哪些语句是操作共享数据的

       修改后代码如下:

    class Bank {
        private int sum;
        Object obj = new Object();
        //同步函数
        public synchronized void add(int n) {
    //        synchronized (obj) {
                sum = sum + n;
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    
                }
                System.out.println("sum="+sum);
    //        }
        }
    }
    class Cus implements Runnable {
        private Bank b = new Bank();
        public void run() {
            for(int x = 0; x < 3; x++) {
                b.add(100);
            }
        }
        
    }
    public class BankDemo {
    
        public static void main(String[] args) {
            Cus c = new Cus();
            Thread t1 = new Thread(c);
            Thread t2 = new Thread(c);
            t1.start();
            t2.start();
        }
    
    }

       

       同步函数用的是哪一个锁呢?

       函数需要被对象调用,那么函数都有一个所属对象引用,就是this。所以同步函数使用的锁是this。

       需求:通过该程序进行验证同步函数使用的锁是this。使用两个线程来买票,一个线程在同步代码块中,一个线程在同步函数中,都在执行买票动作。

       代码如下:

    class Ticket implements Runnable {
        private int tick = 100;
        Object obj = new Object();
        boolean flag = true;
        public void run() {
            if(flag) 
                while(true) {
                    synchronized (this) {
                        if(tick > 0) {
                            //模拟多线程的运行出现的安全问题
                            try {
                                Thread.sleep(10);
                            } catch (InterruptedException e) {
                                
                            }
                            System.out.println(Thread.currentThread().getName()+"...code: "+tick--);
                        }
                    }
                }
            else
                while(true) 
                    show();
        }
        
        public synchronized void show() {//this
            if(tick > 0) {
                //模拟多线程的运行出现的安全问题
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    
                }
                System.out.println(Thread.currentThread().getName()+"...show...: "+tick--);
            }
        }
    }
    
    public class ThisLockDemo {
    
        public static void main(String[] args) {
            Ticket t = new Ticket();
            
            Thread t1 = new Thread(t);//创建一个线程
            Thread t2 = new Thread(t);//创建一个线程
            
            t1.start();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
    
            }
            t.flag = false;
            t2.start();
            
            
    //      Thread t3 = new Thread(t);//创建一个线程
    //      Thread t4 = new Thread(t);//创建一个线程
    //      t3.start();
    //      t4.start();
        }
    
    }

        

       如果同步函数被静态修饰后,使用的锁是什么呢?

       通过验证,发现不再是this,因为静态方法中也不可以定义this。静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象:类名.class,该对象的类型是Class。

       静态的同步方法,使用的锁是该方法所在类的字节码文件对象。即类名.class

       代码示例如下:

    class Ticket implements Runnable {
        private static int tick = 100;
    //  Object obj = new Object();
        boolean flag = true;
        public void run() {
            if(flag) 
                while(true) {
                    synchronized (Ticket_S.class) {
                        if(tick > 0) {
                            //模拟多线程的运行出现的安全问题
                            try {
                                Thread.sleep(10);
                            } catch (InterruptedException e) {
                                
                            }
                            System.out.println(Thread.currentThread().getName()+"...code: "+tick--);
                        }
                    }
                }
            else
                while(true) 
                    show();
        }
        
        public static synchronized void show() {
            if(tick > 0) {
                //模拟多线程的运行出现的安全问题
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    
                }
                System.out.println(Thread.currentThread().getName()+"...show...: "+tick--);
            }
        }
    }
    
    public class StaticMethodDemo {
    
        public static void main(String[] args) {
            Ticket t = new Ticket();
            
            Thread t1 = new Thread(t);//创建一个线程
            Thread t2 = new Thread(t);//创建一个线程
            
            t1.start();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
    
            }
            t.flag = false;
            t2.start();
            
            
    //      Thread t3 = new Thread(t);//创建一个线程
    //      Thread t4 = new Thread(t);//创建一个线程
    //      t3.start();
    //      t4.start();
        }
    
    }

       

       单例设计模式

       面试时主要考的就是懒汉式单例设计模式

    //饿汉式
    /*
    class Single {
        private static final Single s = new Single();
        private Single() {}
        public static Single getInstance() {
            return s;
        }
    }
     */
    //懒汉式(面试)
    class Single {
        private static Single s = null;
        private Single() {}
        public static Single getInstance() {
            if(s==null) {
    //          -->B;
                synchronized(Single.class) {
                    if(s==null)
    //                  -->A;
                        s = new Single();
                }
            }
            return s;
        }
    }

       死锁

       同步中嵌套同步。

       示例1:

    class Ticket implements Runnable {
        private int tick = 100;
        Object obj = new Object();
        boolean flag = true;
        public void run() {
            if(flag) 
                while(true) {
                    synchronized (obj) {
                        show();
                    }
                }
            else
                while(true) 
                    show();
        }
        
        public synchronized void show() {//this
            synchronized (obj) {
                if(tick > 0) {
                    //模拟多线程的运行出现的安全问题
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        
                    }
                    System.out.println(Thread.currentThread().getName()+"...code: "+tick--);
                }
            }
        }
    }
    
    public class DeadLockDemo {
    
        public static void main(String[] args) {
            Ticket t = new Ticket();
            
            Thread t1 = new Thread(t);//创建一个线程
            Thread t2 = new Thread(t);//创建一个线程
            
            t1.start();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
    
            }
            t.flag = false;
            t2.start();
            
            
    //        Thread t3 = new Thread(t);//创建一个线程
    //        Thread t4 = new Thread(t);//创建一个线程
    //        t3.start();
    //        t4.start();
        }
    
    }

       面试题:写一个死锁程序。

       代码如下:

    class TestD implements Runnable {
        
        private boolean flag;
        TestD(boolean flag) {
            this.flag = flag;
        }
        
        public void run() {
            if(flag) {
                while(true) 
                    synchronized (MyLock.locka) {
                        System.out.println("if locka");
                        synchronized (MyLock.lockb) {
                            System.out.println("if lockb");
                        }
                    }
            } else {
                while(true)
                    synchronized (MyLock.lockb) {
                        System.out.println("else lockb");
                        synchronized (MyLock.locka) {
                            System.out.println("else locka");
                        }
                    }
            }
        }
    }
    class MyLock {
        static Object locka = new Object();
        static Object lockb = new Object();
    }
    public class DeadLockTest {
    
        public static void main(String[] args) {
            Thread t1 = new Thread(new TestD(true));
            Thread t2 = new Thread(new TestD(false));
            t1.start();
            t2.start();
        }
    
    }

       线程间通讯

       其实就是多个线程在操作同一个资源,但是操作的动作不同。

       等待唤醒机制

       notifyAll():唤醒线程池中所有等待的线程

       notify():唤醒线程池中第一个等待的线程

       wait()/notify()/notifyAll():都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,因为只有同步才具有锁。

       为什么这些操作线程的方法要定义在Object类中呢?

       因为这些方法在操作同步中线程时,都必须标识它们所操作线程持有的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒,不可以对不同锁中的线程进行唤醒。

       也就是说,等待和唤醒必须是同一个锁。

       而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。

       示例代码如下:

    class Res {
        String name;
        String sex;
        boolean flag = false;
    }
    class Input implements Runnable {
        private Res r;
        Input(Res r) {
            this.r = r;
        }
        public void run() {
            int x = 0;
            
            while(true) {
                synchronized (r) {//锁是任意对象
                    if(r.flag)
                        try {
                            r.wait();
                        } catch (InterruptedException e) {
                            
                        }
                    if(x == 0) {
                        r.name = "mike";
                        r.sex = "man";
                    } else {
                        r.name = "丽丽";
                        r.sex = "女女女女女";
                    }
                    x = (x+1) % 2;
                    r.flag = true;
                    r.notify();//唤醒线程池中第一个等待的线程
                }
                
            }
        }
    }
    class Output implements Runnable {
        private Res r;
        Object obj = new Object();
        Output(Res r) {
            this.r = r;
        }
        public void run() {
            while(true) {
                synchronized (r) {
                    if(!r.flag)
                        try {
                            r.wait();//wait持有r锁的线程
                        } catch (InterruptedException e) {
    
                        }
                    System.out.println(r.name+"..."+r.sex);
                    r.flag = false;
                    r.notify();//notify持有r锁的等待线程
                }
                
            }
        }
    }
    public class InputOutputDemo {
    
        public static void main(String[] args) {
            Res r = new Res();
            
            Input in = new Input(r);
            Output out = new Output(r);
            
            Thread t1 = new Thread(in);
            Thread t2 = new Thread(out);
            
            t1.start();
            t2.start();
        }
    
    }

       以上代码进行优化:

    class Res {
        private String name;
        private String sex;
        private boolean flag = false;
        
        public synchronized void set(String name, String sex) {
            if(flag) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    
                }
            }
            this.name = name;
            this.sex = sex;
            flag = true;
            this.notify();
        }
        
        public synchronized void out() {
            if(!flag) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    
                }
            }
            System.out.println(name+"......"+sex);
            flag = false;
            this.notify();
        }
    }
    class Input implements Runnable {
        private Res r;
        Input(Res r) {
            this.r = r;
        }
        public void run() {
            int x = 0;
            
            while(true) {
                if(x == 0) {
                    r.set("mike", "man");
                } else {
                    r.set("丽丽", "女女女女女");
                }
                x = (x+1) % 2;
            }
        }
    }
    class Output implements Runnable {
        private Res r;
        Object obj = new Object();
        Output(Res r) {
            this.r = r;
        }
        public void run() {
            while(true) {
                r.out();
            }
        }
    }
    public class InputOutputDemo {
    
        public static void main(String[] args) {
            Res r = new Res();
            
            new Thread(new Input(r)).start();
            new Thread(new Output(r)).start();
            /*
            Input in = new Input(r);
            Output out = new Output(r);
            
            Thread t1 = new Thread(in);
            Thread t2 = new Thread(out);
            
            t1.start();
            t2.start();
            */
        }
    
    }

       线程操作案例——生产者和消费者(单个)

       代码如下:

    public class ProducerConsumerDemo {
    
        public static void main(String[] args) {
            Resource r = new Resource();
            
            Producer pro = new Producer(r);
            Consumer con = new Consumer(r);
            
            Thread t1 = new Thread(pro); 
            Thread t2 = new Thread(con);
    
            t1.start();
            t2.start();
        }
    
    }
    class Resource {
        private String name;
        private int count = 1;
        private boolean flag = false;
      
        public synchronized void set(String name) {
            if(flag) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
    
                }
            }
            this.name = name+"--"+count++;
            System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
            flag = true;
            this.notify();
        }
        public synchronized void out() {
            if(!flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
    
                }
            }
            System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);
            flag = false;
            notify();
        }
    }
    class Producer implements Runnable {
        private Resource res;
        Producer(Resource res) {
            this.res = res;
        }
        
        public void run() {
            while(true) {
                res.set("+商品+");
            }
        }
    }
    class Consumer implements Runnable {
        private Resource res;
        Consumer(Resource res) {
            this.res = res;
        }
        public void run() {
            while(true) {
                res.out();
            }
        }
    }

       生产者和消费者(多个)

       运行以上代码会产生异常情况:重复生产或重复消费。

       优化后代码如下:

    public class ProducerConsumerDemo {
    
        public static void main(String[] args) {
            Resource r = new Resource();
            
            Producer pro = new Producer(r);
            Consumer con = new Consumer(r);
            
            Thread t1 = new Thread(pro);
            Thread t2 = new Thread(pro);
            Thread t3 = new Thread(con);
            Thread t4 = new Thread(con);
            
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    
    }
    class Resource {
        private String name;
        private int count = 1;
        private boolean flag = false;
        //(生产者)t1 t2
        public synchronized void set(String name) {
            while(flag) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
    
                }
            }
            this.name = name+"--"+count++;
            System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
            flag = true;
            this.notifyAll();
        }
        //(消费者)t3 t4
        public synchronized void out() {
            while(!flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
    
                }
            }
            System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);
            flag = false;
            notifyAll();
        }
    }
    class Producer implements Runnable {
        private Resource res;
        Producer(Resource res) {
            this.res = res;
        }
        
        public void run() {
            while(true) {
                res.set("+商品+");
            }
        }
    }
    class Consumer implements Runnable {
        private Resource res;
        Consumer(Resource res) {
            this.res = res;
        }
        public void run() {
            while(true) {
                res.out();
            }
        }
    }

       对于多个生产者和消费者,为什么一定要定义while判断标记?

       原因:让被唤醒的线程再一次判断标记。

       为什么定义notifyAll?

       因为需要唤醒对方线程,因为只用notify,容易出现只唤醒本方线程的情况,导致程序中的所有线程都等待。

       JDK1.5版本中提供了多线程的升级解决方案。

    1. 将同步synchronized替换成了显示的Lock操作。
    2. 将Object中的wait/notify/notifyAll替换成Condition对象。该对象可以通过Lock锁进行获取。

       该示例实现了本方只唤醒对方的操作import java.util.concurrent.locks.Conditioimport java.util.concurrent.locks.Lock;

    import java.util.concurrent.locks.ReentrantLock;
    
    public class ProducerConsumerDemo1 {
    
        public static void main(String[] args) {
            Resource1 r = new Resource1();
            
            Producer1 pro = new Producer1(r);
            Consumer1 con = new Consumer1(r);
            
            Thread t1 = new Thread(pro);
            Thread t2 = new Thread(pro);
            Thread t3 = new Thread(con);
            Thread t4 = new Thread(con);
            
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    
    }
    class Resource1 {
        private String name;
        private int count = 1;
        private boolean flag = false;
        
        private Lock lock = new ReentrantLock();
        
    //返回绑定到此Lock实例的新Condition实例
    //Lock可以支持多个相关的 Condition对象
    private Condition condition_pro = lock.newCondition(); private Condition condition_con = lock.newCondition(); //(生产者)t1 t2 public void set(String name) throws InterruptedException { lock.lock(); try { while(flag) { condition_pro.await(); //抛出异常 } this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name); flag = true; condition_con.signal(); } finally { lock.unlock();//释放锁资源的动作一定要执行 } } //(消费者)t3 t4 public void out() throws InterruptedException { lock.lock(); try { while(!flag) { condition_con.await();//抛出异常 } System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name); flag = false; condition_pro.signal(); } finally { lock.unlock();//释放锁资源 } } } class Producer1 implements Runnable { private Resource1 res; Producer1(Resource1 res) { this.res = res; } public void run() { while(true) { try { res.set("+商品+"); } catch (InterruptedException e) { } } } } class Consumer1 implements Runnable { private Resource1 res; Consumer1(Resource1 res) { this.res = res; } public void run() { while(true) { try { res.out(); } catch (InterruptedException e) { } } } }

       如何停止线程?

       stop()已经过时,只有一种,即run()结束。

       开启多线程运行,运行代码通常都是循环结构。只要控制住循环,就可以让run()结束,也就是线程结束。

       特殊情况:当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束。

       当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。Thread类中提供了该方法:interrupt()。

       示例代码如下:

    class StopThread implements Runnable {
        private boolean flag = true;
        public synchronized void run() {
            while(flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName()+"...Exception");
                    flag = false;
                }
                System.out.println(Thread.currentThread().getName()+"...run");
            }
        }
        public void changeFlag() {
            flag = false;
        }
    }
    public class StopThreadDemo {
    
        public static void main(String[] args) {
            StopThread st = new StopThread();
            
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(st);
            
            t1.start();
            t2.start();
            
            int num = 0;
            while(true) {
                if(num++ == 60) {
                    //st.changeFlag();
                    t1.interrupt();
                    t2.interrupt();
                    break;
                }
                System.out.println(Thread.currentThread().getName()+"..........."+num);
            }
            System.out.println("over");
        }
    
    }

       

       我们看到的都是前台线程,主线程就是前台线程。

       setDaemon(boolean):将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java虚拟机退出。

       注意:该方法必须在启动线程前调用。

       示例代码:

    class StopThread1 implements Runnable {
        private boolean flag = true;
        public synchronized void run() {
            while(flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName()+"...Exception");
                    flag = false;
                }
                System.out.println(Thread.currentThread().getName()+"...run");
            }
        }
        public void changeFlag() {
            flag = false;
        }
    }
    public class StopThreadDemo1 {
    
        public static void main(String[] args) {
            StopThread1 st = new StopThread1();
            
            Thread t1 = new Thread(st);
            Thread t2 = new Thread(st);
            
            t1.setDaemon(true);
            t2.setDaemon(true);
            t1.start();
            t2.start();
            
            int num = 0;
            while(true) {
                if(num++ == 60) {
                    //st.changeFlag();
                    //t1.interrupt();
                    //t2.interrupt();
                    break;
                }
                System.out.println(Thread.currentThread().getName()+"..........."+num);
            }
            System.out.println("over");
        }
    
    }

       join

       当A线程执行到了B线程的join()时,A就会等待,等B线程都执行完,A才会执行。join可以用来临时加入线程执行。

       示例代码:

    class DemoJ implements Runnable {
        public void run() {
            for(int x = 0; x < 70; x++) {
                System.out.println(Thread.currentThread().toString()+"......"+x);
                Thread.yield();//将CPU的执行权释放出去
            }
        }
    }
    public class JoinMethodDemo {
    
        public static void main(String[] args) throws InterruptedException {
            DemoJ d = new DemoJ();
            
            Thread t1 = new Thread(d);
            Thread t2 = new Thread(d);
            
            t1.start();
            
            //t1.setPriority(Thread.MAX_PRIORITY);//设置进程优先级,默认为5
            //t1.join();
            
            t2.start();
            
            //t1.join();
            
            for(int x = 0; x < 80; x++) {
                //System.out.println("main...."+x);
            }
            System.out.println("over");
        }
    
    }

       实际开发时,怎么使用多线程呢?以下例进行讲解,假设main()里有3段循环代码运行。可用多线程来实现(代码如下):

    public class DevThreadTest {
    
        public static void main(String[] args) {
            //匿名内部类
            new Thread(){
                public void run() {
                    for(int x = 0; x < 100; x++) {
                        System.out.println(Thread.currentThread().getName()+"....."+x);
                    }
                }
            }.start();
            
            for(int x = 0; x < 100; x++) {
                System.out.println(Thread.currentThread().getName()+"....."+x);
            }
            
            Runnable r =  new Runnable() {
                
                @Override
                public void run() {
                    for(int x = 0; x < 100; x++) {
                        System.out.println(Thread.currentThread().getName()+"....."+x);
                    }
                }
            };
            new Thread(r).start();
        }
    
    }
  • 相关阅读:
    Sqlite官方的查询优化文档
    VC++动态链接库(DLL)编程深入浅出(三)转
    用Python查询手机号码归属地
    Delphi使用迅雷的开放下载引擎下载
    Android基础之一
    VC++动态链接库深入浅出(转)
    在Python脚本中使用Delphi控件
    Python与其他语言结合的参数转换函数PyArg_ParseTuple()
    设计模式之模板方法模式(Template)
    设计模式之简单工厂模式(Simple Factory)
  • 原文地址:https://www.cnblogs.com/yerenyuan/p/5224874.html
Copyright © 2011-2022 走看看