多线程增加效率

  • 并行, 就是多个任务同时进行, 多核cpu同时执行
  • 并发, 多个任务轮流进行, cpu一个一个的执行

证明 JVM 是多线程的

垃圾回收和main线程间隔执行

public class Demo1_Thread {
    public static void main(String[] args) {
        for(int i=0; i < 10000000 ;i++){
            new Demo();
        }
        for(int i=0; i < 10000 ; i++){
            System.out.println("主线程");
        }
    }
}
class Demo{
    @Override
    protected void finalize() throws Throwable {
        System.out.println("垃圾被回收了");
    }
}

继承Thread 开启一个线程

  • 实际run() 方法
  • start() 开启线程
public class Demo2_ExtendsThread {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
//        mt.run();
        mt.start();
        for (int i=0; i <10000 ; i++){
            System.out.println(i+"bbbbbbbbbbbbb");
        }
    }
}

class MyThread extends Thread{
    @Override
    public void run() {
        for(int i=0; i < 10000 ;i++){
            System.out.println(i+"aaaaaaaaaaaaaaa");
        }
    }
}

实际 Runnable 接口的类

  • 实际Runnable类, 类作为参数传递给线程, start() 开启线程
public class Demo3_Runnable {
    public static void main(String[] args) {
        MyRunnable d =  new MyRunnable();
        Thread t = new Thread(d);
        t.start();
        for(int i=0; i < 10000 ;i++){
            System.out.println(i+"bbbbbbbbbbbbbbb");
        }

    }
}
class MyRunnable implements Runnable{
    @Override
    public void run() {
        for(int i=0; i < 10000 ;i++){
            System.out.println(i+"aaa");
        }
    }
}

多线程的2种区别

  • 继承 Thread: 由于子类重写了Thread类的run()方法, 当调用start()时, 直接找子类的run()方法
  • 实际 Runnable: 构造函数中传入了Runnable的引用, 成员变量记住了它, start()调用run() 方法时内部判断成员变量Runnable的引用是否为空,
    不为空看的Runnable的run(), 运行时是子类的run()方法.
  • 继承Thread实现简单, 方便使用, 有父类则不能使用这种方法
  • 有父类时可以实际Runnable 接口实现多线程, 对继承Thread的补充, 使用时必须获取线程对象, 使用复杂

匿名内类实现多线程的方法

public class Demo4_NoNameThread {
    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                for(int i=0; i<100000 ;i++){
                    System.out.println("aaaaaa");
                }
            }
        }.start();
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<10000;i++){
                    System.out.println("bbbbbbbbbbbbbbbbbbb");
                }
            }
        });
        t.start();
    }
}

匿名内部类设置线程名字

public class Demo5_ThreadName {
    public static void main(String[] args) {
//        demo1();
        Thread t =  new Thread(){
            @Override
            public void run() {
//                this.setName("小明");
                System.out.println(this.getName()+"aaaaa");
            }
        };
        t.setName("李明");
        t.start();
        new Thread(){
            @Override
            public void run() {
                this.setName("小明");
                System.out.println(this.getName()+"aaaaa");
            }
        }.start();
    }

    private static void demo1() {
        new Thread("小明"){
            @Override
            public void run() {
                System.out.println(this.getName()+ "aaaaa");
            }
        }.start();
        new Thread("小红"){
            @Override
            public void run() {
                System.out.println(this.getName()+ "bbbbbb");
            }
        }.start();
    }
}

也可调用setName更改名称 获取本类的引用Thread.currentThread()

public class Demo6_GetName {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        Thread.currentThread().setName("主线程");
        System.out.println(Thread.currentThread().getName());
        new Thread( new Runnable() {

            @Override
            public void run() {
                System.out.println("dkf"+Thread.currentThread().getName());
            }
        }).start();
    }
}

休眠线程

public class Demo7_ThreadSleep {
    public static void main(String[] args) throws InterruptedException {
//        demo1();
        new Thread(){
            @Override
            public void run() {
                for (int i=0;i<10;i++) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName()+"a");
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                for (int i=0;i<10;i++) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName()+"bbbb");
                }
            }
        }.start();
    }

    private static void demo1() throws InterruptedException {
        for (int i=0; i<100;i++){
            Thread.sleep(1000);
            System.out.println(i);
        }
    }
}

守护线程

  • 守护线程不会单独执行, 其他线程执行完了, 自动结束守护线程
  • final void setDaemon(boolean on)
public class Demo8_GudarThread {
    public static void main(String[] args) {
        Thread t1 = new Thread(){
            @Override
            public void run() {
                for (int i =0;i<2;i++){
                    System.out.println(getName()+i);
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                for (int i =0;i<50;i++){
                    System.out.println(getName()+"aaaaaaaaaaa");
                }
            }
        };
        t2.setDaemon(true);
        t1.start();
        t2.start();
    }
}

加入线程

  • final void join() throws InterruptedException 插队执行线程
  • final void join(long millis) throws InterruptedException 插队执行m毫秒后, 再交其他线程
public class Demo9_ThreadJoin {
    public static void main(String[] args) {
        Thread t1 = new Thread(){
            @Override
            public void run() {
                for (int i =0;i<100;i++){
                    System.out.println(getName()+i);
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                for (int i =0;i<100;i++){
                    if(i == 2) {
                        try {
                            t1.join();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(getName()+"aaaaaaaaaaa");
                }
            }
        };
        t1.start();
        t2.start();

    }
}

礼让线程, 了解即可

public class Demo10_Yield {
    public static void main(String[] args) {
        new MyThread2().start();
        new MyThread2().start();

    }
}

class MyThread2 extends Thread{
    @Override
    public void run() {
        for (int i=0;i<1000;i++) {
            if(0 == i%10){
                Thread.yield();
            }
            System.out.println(getName()+" "+i);
        }
    }
}

线程优先级

  • final void setPriority(int newPriority) 设置线程的优先级, 小范围1-10
public class Demo11_Priority {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                for (int i=0;i<100;i++){
                    System.out.println(getName()+"aaa");
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                for (int i=0;i<100;i++){
                    System.out.println(getName()+"bbb");
                }
            }
        };
        t2.setPriority(Thread.MIN_PRIORITY);
        t.setPriority(Thread.MAX_PRIORITY);
        t.start();
        t2.start();
    }
}

线程同步

  • 当多线程执行到一段代码块时, 不希望线程切换其他线程
  • synchronized 关键字锁对象到定义一段代码块, 同步代码块
  • 锁对象是任意的, 锁对象不能是匿名对象
public class Demo1_Synchronized {
    public static void main(String[] args) {
        Printer p = new Printer();
        new Thread(){
            @Override
            public void run() {
                while (true) {
                    p.eatApple();
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                while (true) {
                    p.eatMeet();
                }
            }
        }.start();
    }
}

class Printer{
    Demo d = new Demo();
    public  void eatApple(){
        synchronized (d) {
            System.out.print("a");
            System.out.print("a");
            System.out.print("a");
            System.out.print("a");
            System.out.print("a");
            System.out.print("a");
            System.out.println();
        }
    }
    public  void eatMeet(){
        synchronized (d) {
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.println();
        }
    }
}
class Demo{}

同步方法

  • 非静态方法的锁对象是this
  • 静态方法的锁对象是字节码对象
package com.lizicai.sync;

public class Demo2_Syn {
    public static void main(String[] args) {
        Printer2 p = new Printer2();
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    p.eatApple();
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                while (true) {
                    p.eatMeet();
                }
            }
        }.start();
    }
}
class Printer2{
    Demo d = new Demo();
    synchronized public  void eatApple(){
        System.out.print("a");
        System.out.print("a");
        System.out.print("a");
        System.out.print("a");
        System.out.print("a");
        System.out.print("a");
        System.out.println();
    }

    public  void eatMeet(){
        synchronized (this) {
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.println();
        }
    }
}
class Demo2{
}
public class Demo3_SynStaticMethod {
    public static void main(String[] args) {
        Printer3 p = new Printer3();
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    Printer3.eatApple();
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                while (true) {
                    Printer3.eatMeet();
                }
            }
        }.start();
    }
}
class Printer3{
    Demo d = new Demo();
    synchronized public static void eatApple(){
        System.out.print("a");
        System.out.print("a");
        System.out.print("a");
        System.out.print("a");
        System.out.print("a");
        System.out.print("a");
        System.out.println();
    }

    public static void eatMeet(){
        synchronized (Printer3.class) {
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.print("b");
            System.out.println();
        }
    }
}

模拟卖票

  • 使用唯一对象字节对象作为锁
  • 或者使用静态的对象作为锁
public class Demo4_SynSoldTicket {
    public static void main(String[] args) {
        new Ticket().start();
        new Ticket().start();
        new Ticket().start();
        new Ticket().start();

    }
}
class Ticket extends Thread{
    private static int tickets = 100;
    private static Object obj = new Object();

    @Override
    public void run() {
        while (true){
//            synchronized (obj){
            synchronized (Ticket.class) {
                if( tickets <= 0){
                    break;
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(getName()+"-Ticket"+tickets--);
            }
        }
    }
}

火车站卖票 Runnable接口方式

  • 多次启动start()非法
public class Demo5_SynSoldTicket {
    public static void main(String[] args) {
        Ticket2 tc = new Ticket2();
        new Thread(tc).start();
        new Thread(tc).start();
        new Thread(tc).start();
        new Thread(tc).start();
    }
}
class Ticket2 implements Runnable{

    private int tickets = 100;
    @Override
    public void run() {
        while (true) {
            // Ticket2.class 也可
//            synchronized (Ticket2.class) {
            synchronized (this) {
                if( tickets <= 0){
                    break;
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"-Ticket"+tickets--);
            }
        }
    }
}

多线程死锁

  • 避免同步代码块嵌套, 容易造成死锁
public class Demo6_SynDead {
    private static String s1 = "筷子左";
    private static String s2 = "筷子右";
    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                while (true){
                    synchronized (s1){
                        System.out.println(getName()+"..."+s1+"等待"+s2);
                        synchronized (s2){
                            System.out.println(getName()+"...拿到"+s1+s2+"开饭");
                        }
                    }
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                while (true){
                    synchronized (s2){
                        System.out.println(getName()+"..."+s2+"等待"+s1);
                        synchronized (s1){
                            System.out.println(getName()+"...拿到"+s2+s1+"开饭");
                        }
                    }
                }
            }
        }.start();
    }
}

线程安全的类

  • Vector 线程安全的, ArrayList线程不安全
  • StringBuffer 线程安全的, StringBuilder 线程不安全的
  • Hashtable 线程安全的, HashMap 线程不安全的
  • Connections 中有synchronizedList 等方法返回线程安全的列表ArrayList