【JAVA基础-多线程】- 多线程(补充)

线程控制的常见方法

  • sleep 休眠线程
    public static native void sleep(long millis) throws InterruptedException;
  • join 加入线程,等待该线程终止,Waits for this thread to die
    public final void join() throws InterruptedException
    public final synchronized void join(long millis, int nanos) throws InterruptedException
  • yield 礼让线程,暂停当前正在执行的线程对象(转变为就绪状态),并执行其他线程
    public static native void yield();
  • setDaemon 将该线程设置为守护线程或用户线程
    1. setDaemon(false) 设置为用户线程,用于为系统中的其它对象和线程提供服务;setDaemon(true)设置为守护线程,在没有用户线程服务时会自动离开;如果不设置此属性,默认用户线程。
    2. setDaemon 需要在start方法调用之前调用使用
    3. 用Thread.isDaemon()来返回是否是守护线程
    4. 如果jvm中都是守护进程,当前jvm将退出
public class DaemonTest extends Thread {

    @Override
    public void run() {
        for (int i = 1; ; i++) { // 代码一直会执行
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);
        }
    }

    public static void main(String[] args) {
        DaemonTest daemonTest = new DaemonTest();
        daemonTest.setDaemon(true); // 设置为false,那么这个程序就是死循环,没有退出条件。设置为true,即主线程结束,daemonTest线程也结束
        daemonTest.start();

        System.out.println("isDaemon = " + daemonTest.isDaemon());

        try {
            System.in.read();// 接受输入,使程序在此停顿,一旦接受到用户输入,main线程结束,守护线程自动结束
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

线程调度和优先级

线程的调度:
* 分时调度
* 抢占式调度(Java采用的该调度方式)

获取和设置线程优先级
* 默认是5
* 范围是1-10
线程优先级高仅仅表示线程获取CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果
如何获取线程对象的优先级?
public final int getPriority():返回线程对象的优先级
如何设置线程对象的优先级呢?
public final void setPriority(int newPriority):更改线程的优先级

线程生命周期

  • 新建:创建线程对象
  • 就绪:有执行资格,没有执行权
  • 运行:有执行资格,有执行权
  • 阻塞:
    由于一些操作让线程处于该状态。没有执行资格,没有执行权
    而另一些操作却可以把它给激活,激活后处于就绪状态
  • 死亡: 线程对象变成垃圾,等待被回收
image.png

多线程安全问题原因

也就是我们判断一个程序是否是线程安全问题的依据

  1. 是否是多线程环境
  2. 是否有共享数据
  3. 是否是多条语句操作共享数据

同步解决线程安全问题

  1. 同步代码块
        synchronized(对象) {
                需要被同步的代码;
            }

这里的锁对象可以是任意对象
把多条语句操作共享数据的代码的部分给包起来
把多条语句操作共享数据的代码的部分给包起来
多个线程必须是同一把锁

  1. 同步方法,这里的锁对象是this

  2. 静态同步方法,这里的锁对象是当前类的字节码文件对象

同步好处:解决了多线程安全的问题
同步弊端:当线程多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

线程安全类

  1. StringBuffer
  2. Vector
  3. HashTable
  4. 如何把一个线程不安全的集合类变成一个线程安全的集合类
    用Collections工具类的方法即可
    List list2 = Collections.synchronizedList(new ArrayList()); // 线程安全

Lock 锁

关于锁的一个Demo:

image.png
public class Student {

    private String name;
    private int age;
    private boolean flag; // 默认情况下没有数据,如果是true,说明有数据

    public synchronized void set(String name, int age) {
        // 如果有数据,就等待
        if (this.flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 设置数据
        this.name = name;
        this.age = age;

        // 修改标记
        this.flag = true;
        this.notify();
    }

    public synchronized void get() {
        // 如果没有数据,就等待
        if (!this.flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 获取数据
        System.out.println(this.name + "--" + this.age);

        // 修改数据
        this.flag = false;
        this.notify();
    }
}
public class GetThread implements Runnable {

    private Student s;

    public GetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            s.get();
        }
    }
}
public class SetThread implements Runnable{

    private Student s;

    public SetThread(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            s.set();
        }
    }
}
public class MainDemo {

    public static void main(String[] args) throws Exception {
        Student student = new Student();

        SetThread setThread = new SetThread(student);
        GetThread getThread = new GetThread(student);

        Thread thread01 = new Thread(setThread);
        Thread thread02 = new Thread(getThread);

        thread01.start();
        thread02.start();

    }
}

多线程 例子

public class SellTicket implements Runnable {
    // 为了让多个线程共享这100张票,应该使用静态修饰
    private static int tickets = 100;

    @Override
    public void run() {

        while (true) {
            synchronized (SellTicket.class) {
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets-- + "张票");
                } else {
                    break;
                }
            }
        }
    }
}
public class MainDemo {

    public static void main(String[] args) throws Exception {
        SellTicket sellTicket = new SellTicket();
        SellTicket sellTicket2 = new SellTicket();
        SellTicket sellTicket3 = new SellTicket();

        Thread thread01 = new Thread(sellTicket);
        Thread thread02 = new Thread(sellTicket2);
        Thread thread03 = new Thread(sellTicket3);

        thread01.start();
        thread02.start();
        thread03.start();
    }
}

你可能感兴趣的:(【JAVA基础-多线程】- 多线程(补充))