多线程

   进程  

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

   线程

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

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

   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();
    }

}
原文地址:https://www.cnblogs.com/yerenyuan/p/5224874.html