• JavaSE多线程


    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());
            }
        }
    }
    
    
  • 相关阅读:
    软件工程 四则运算 基于控制台。
    新学期 新气象
    http://www.cnblogs.com/091JN/
    201421123091 ONLY-JN
    201421123091 ONLY-JN
    C语言课程学习的总结
    实验13——结构体、文件的基本应用
    实验12——指针的基础应用2
    实验11——指针的基础应用
    实验十——一维数组的定义及引用
  • 原文地址:https://www.cnblogs.com/Hot-machine/p/13190348.html
Copyright © 2020-2023  润新知