张嘉锡V

导航

 

Java多线程

实现多线程的几种方式

继承Thread类

  • 自定义线程类继承Thread类
  • 重写run()方法
  • 创建线程对象,调用start()方法启动线程
public class MyThread entends Thread {
    @Override
    public void run() {
        // ...
    }
}

public static void main(String[] args) {
    MyThread mt = new MyThread();
    mt.start();
}

实现Runnable接口

  • 实现Runnable接口
  • 实现run()方法
  • 创建线程对象,调用start()方法
public class MyRunnable implements Runnable {
    @override
    public void run() {
        // ...
    }
}

public static main(String[] args) {
    MyRunnable mr = new MyRunnable();
    new Thread(mr).start();
}

实现Callable接口

  • 实现Callable接口,需要返回值类型
  • 重写call方法,需要抛出异常
ExecutorService ser = Executors.newFixedThreadPool(1);
Future<boolean> result = ser.submit(t1);
boolean r = result.get();
ser.shutdownNow();
Lambda表达式
new Thread(()->{
    // ...
}).start();

线程的状态:创建、就绪、阻塞、运行、死亡

stop:使用标志位

public class testStop implements Runnable {
    // 标志位
    private boolean flag = true;
    @Override
    public void run() {
        while(flag) {
            System.out.println("running ");
        }
    }
    // 提供标示
    public void stop() {
        this.flag = false;
    }

    public static void main(String[] args) {
        testStop ts = new testStop();
        new Thread(ts).start();
        // 主线程
        for(int i = 1; i <= 50; i++) {
            System.out.println("main " + i);
            // 主线程i=30, 停止运行ts
            if(i == 30) {
                ts.stop();
                System.out.println("stop!");
            }
        }
    }
}

sleep: 线程休眠, 线程阻塞的毫秒数

  • 每个对象都有一个锁,sleep不会释放锁。
public class testSleep {
    // sleep 存在异常InterruptedException
    public static void countDown() throws InterruptedException {
        int n = 10;
        while(n > 0) {
            Thread.sleep(100);
            n--;
        }
    }
    public static void main(String[] args) {
        Date time = new Date(System.currentTimeMillis());
        try {
            System.out.println(new SimpleDateFormat("hh:mm:ss").format(System.currentTimeMillis()));
            countDown();
            time = new Date(System.currentTimeMillis());
            System.out.println(new SimpleDateFormat("hh:mm:ss").format(System.currentTimeMillis()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

yield: 线程礼让,当前正在执行的线程暂停,不阻塞,让CPU重新调度

public class testYield {
    public static void main(String[] args) {
        MyYield my = new MyYield();
        new Thread(my,"a").start();
        new Thread(my, "b").start();
    }
}

class MyYield implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " at work");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + " out of work");
    }
}

Join: 线程合并,先执行此线程,其他线程阻塞

public class testJoin {
    public static void main(String[] args) throws InterruptedException {
        MyJoin mj = new MyJoin();
        Thread td = new Thread(mj);
        td.start();

        for(int i = 0; i < 10; i++) {
            System.out.println("main: " + i);
            if(i == 8) td.join();
        }
    }
}

class MyJoin implements Runnable {
    @Override
    public void run() {
        for(int i = 1; i <= 100; i++) {
            System.out.println("vip: " + i);
        }
    }
}

线程同步:

第一个线程访问,锁定同步监视器,执行其中的代码
第二个线程访问,发现同步监视器被锁定,无法访问
第一个线程访问完毕,解锁同步监视器
第二个线程访问,锁定访问

  • synchronized:同步方法
  • synchronize(Obj):同步块

生产者/消费者模式

方式一:管程法

public class testPC {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Productor(container).start();
        new Consumer(container).start();
    }

}

class Productor extends Thread {
    SynContainer container;
    public Productor(SynContainer container) {
        this.container = container;
    }
    public void run() {
        for(int i = 0; i < 100; i++) {
            container.push(new Chicken(i));
            System.out.println("生产了" + i + "只鸡");
        }
    }
}

class Consumer extends Thread {
    SynContainer container;
    public Consumer(SynContainer container) {
        this.container = container;
    }
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了-->" + container.pop().id + "只鸡");
        }
    }
}
class Chicken {
    int id;
    public Chicken(int id) {
        this.id = id;
    }
}

class SynContainer {
    Chicken[] chickens = new Chicken[10];
    int count = 0;
    public synchronized void push(Chicken chicken) {
        if (count == chickens.length) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        chickens[count] = chicken;
        count++;
        this.notifyAll();
    }
    public synchronized Chicken pop() {
        if(count == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        count--;
        Chicken chicken =  chickens[count];
        return chicken;
    }
}

java中的notify和notifyAll区别

  • 锁池:假设线程A已经拥有了某个对象的锁,而其他线程想要调用这个对象的synchronized方法,由于这些线程在进入对象的synchronized方法之前必须获得该对象的锁的拥有权,但该线程被线程A占用,因此,这些线程进入了该对象的锁池。

  • 等待池:假设一个线程A调用某个对象的wait()方法,线程A会释放该对象的锁,进入到该对象的等待池

  • 如果线程调用了该对象的wait()方法,线程便会处于该对象的等待池中,等待池中的线程不会竞争该对象的锁

  • 当有线程调用对象的notifyAll()方法或者notify()方法,随机唤醒一个wait线程,被唤醒的线程会进入该对象的锁池中,锁池中的线程会竞争该对象锁。

  • 优先级高的线程竞争到对象锁的概率大,若某个线程没有竞争到该对象锁,它会留在锁池中,唯有线程再次调用wait()方法,他才会重新回到等待池中。而竞争到对象锁的线程继续向下执行,直到执行完synchronized代码块,释放该对象的锁,锁池中的锁继续竞争。

方式二:信号灯法,标志位

public class testPC2 {
    public static void main(String[] args) {
        Tv tv = new Tv();
        new Player(tv).start();
        new Watcher((tv)).start();
    }
}

class Player extends Thread {
    Tv tv;
    public Player(Tv tv) {
        this.tv = tv;
    }
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i % 2 == 0) {
                this.tv.play("abc");
            } else {
                this.tv.play("def");
            }
        }
    }
}

class Watcher extends Thread {
    Tv tv;
    public Watcher(Tv tv) {
        this.tv = tv;
    }
    public void run() {
        for (int i = 0; i < 20; i++) {
            tv.watch();
        }
    }
}

class Tv {
    String voice;
    // 标志位
    boolean flag = true;
    public synchronized void play(String voice) {
        if(!flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员表演了:" + voice);
        this.voice = voice;
        this.flag = !this.flag;
    }
    public synchronized void watch() {
        if(flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观看了:" + voice);
        this.notifyAll();
        this.flag = !this.flag;
    }
}

线程池

  • 传入Runnable接口
public class testpool {
    public static void main(String[] args) {
        // 参数为线程池中线程个数
        ExecutorService ser = Executors.newFixedThreadPool(10);

        ser.execute(new MyThread());
        ser.execute(new MyThread());
        ser.execute(new MyThread());
        ser.execute(new MyThread());
        // 关闭
        ser.shutdown();
    }
}
class MyThread implements Runnable {
    @Override
    public void run() {
        for(int i = 0; i < 4; i++) {
            System.out.println(Thread.currentThread().getName());
        }
    }
}

posted on 2020-06-24 22:16  张嘉锡V  阅读(61)  评论(0编辑  收藏  举报