多线程

1、线程的使用

1、创建:

继承线程接口:extends Thread

实现运行接口:implements Runnable

使用Callable和futrue创建线程:

package com.zhou.controller;

public class Window extends Thread {

    private int ticket = 100;

    public static void main(String[] args) {

        Window window = new Window();

        // window 线程运行的目标对象
        Thread t1 = new Thread(window);
        Thread t2 = new Thread(window);
        Thread t3 = new Thread(window);

        // 三个窗口在抢票
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }

    @Override
    public void run() {
        while (true) {
            if (ticket > 0) {

                try {
                    Thread.sleep(100L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
                ticket--;
            }
        }
    }
}

结果:

...
... 
...
... 
窗口1:卖票,票号为:7
窗口3:卖票,票号为:6
窗口2:卖票,票号为:5
窗口1:卖票,票号为:4
窗口1:卖票,票号为:4
窗口2:卖票,票号为:2
窗口1:卖票,票号为:1
窗口3:卖票,票号为:0
窗口2:卖票,票号为:-1

2、同步机制

1、方式一:同步代码块(synchronized)

synchronized(同步监视器) {
	
}
  1. 说明:操作共享数据的代码即为需要被同步的代码。
  2. 共享数据:多个线程共同操作的变量。比如:ticket
  3. 同步监控器:俗称“”,任何一个类的对象都可以充当锁。

这里使用 new Object()对象充当锁,

synchronized(object){ ..//锁住这里的代码块..}

为了确保三个windows 对象使用的是同一个锁,必须进行obj对象的唯一和改为static静态的。

package com.zhou.controller;

public class Window extends Thread {

    private int ticket = 100;
    private static Object obj = new Object();

    public static void main(String[] args) {

        Window window = new Window();

        // window 线程运行的目标对象
        Thread t1 = new Thread(window);
        Thread t2 = new Thread(window);
        Thread t3 = new Thread(window);

        // 三个窗口在抢票
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }

    @Override
    public void run() {
        while (true) {
            synchronized(obj) {
                if (ticket > 0) {

                    try {
                        Thread.sleep(100L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}

问题:为什么不把while(true)锁进去,锁住的话只有一个窗口在执行。

2、方式二:锁代码块(synchronized)

package com.zhou.controller;

public class Window extends Thread {

    private static int ticket = 100;

    public static void main(String[] args) {

        Window window = new Window();
        Thread t1 = new Thread(window);
        Thread t2 = new Thread(window);
        Thread t3 = new Thread(window);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();



    }

    @Override
    public void run() {
        while (true) {
            show();
        }
    }

    private static synchronized void show() {
        if (ticket > 0) {

            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
            ticket--;
        }
    }
}

总结:

1.同步方法仍然涉及同步监视器,只是我们不需要显示的声明;
2.非静态的同步方法,同步监视器是:this
静态的同步方法同步监视器是:当前类本身。

3、方式三:lock锁

创建锁 :private Reentranlock lock = new ReentranLock();

手动开启和关闭锁:try{ lock.lock(); // 开锁 } finally

package com.zhou.controller;

import java.util.concurrent.locks.ReentrantLock;

public class Window extends Thread {

    private static int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {

        Window window = new Window();
        Thread t1 = new Thread(window);
        Thread t2 = new Thread(window);
        Thread t3 = new Thread(window);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();



    }

    @Override
    public void run() {
        while (true) {

            try {
                lock.lock(); // 手动调用lock锁

                if (ticket > 0) {

                    try {
                        Thread.sleep(100L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
                    ticket--;
                }
            } finally {
                lock.unlock(); // 手动解锁
            }

        }
    }
}

3、synchronized和lock方式的异同

相同:二者都可以解决线程安全问题

不同:

synchronized 执行相应代码后,自动四方同步监听器。

lock 需要手动启动同步lock(),同步结束后也需要手动实现unlock();

4、线程的5中状态:

1、初始(new)

刚创建的线程

2、就绪(Runnable):调用了start()

线程被其他线程调用了该线程对象的start()方法进入就绪状态等待cpu随机的时间调用线程的run()方法

3、运行(Running):线程获得cpu时间片(timeslice)

正在执行程序代码

4、阻塞(Blocked):因某种原因放弃cpu使用权(wait()、sleep())

放弃cpu使用权:让出了cpu timeslice,暂时停止运行,直到线程进入就绪(Runnable)状态,才有机会再次获得cpu timeslice,然后转到运行(Running)状态。

1、等待阻塞:线程执行了.wait()方法。

jvm把该线程放入到等待队列(waitting queue)中

2、同步阻塞:获取对象同步锁时,该锁被其他线程占用。

jvm把该线程放入锁池(lock pool)中

3、其他阻塞:运行(running)的线程执行 sleep()、t.join()方法。

5、死亡(Dead):线run()、main()方法执行结束。

posted @ 2020-08-21 15:47  一座塔一盏灯  阅读(105)  评论(0编辑  收藏  举报