线程控制的常见方法
- 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 将该线程设置为守护线程或用户线程
- setDaemon(false) 设置为用户线程,用于为系统中的其它对象和线程提供服务;setDaemon(true)设置为守护线程,在没有用户线程服务时会自动离开;如果不设置此属性,默认用户线程。
- setDaemon 需要在start方法调用之前调用使用
- 用Thread.isDaemon()来返回是否是守护线程
- 如果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
多线程安全问题原因
也就是我们判断一个程序是否是线程安全问题的依据
- 是否是多线程环境
- 是否有共享数据
- 是否是多条语句操作共享数据
同步解决线程安全问题
- 同步代码块
synchronized(对象) {
需要被同步的代码;
}
这里的锁对象可以是任意对象
把多条语句操作共享数据的代码的部分给包起来
把多条语句操作共享数据的代码的部分给包起来
多个线程必须是同一把锁
同步方法,这里的锁对象是this
静态同步方法,这里的锁对象是当前类的字节码文件对象
同步好处:解决了多线程安全的问题
同步弊端:当线程多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
线程安全类
- StringBuffer
- Vector
- HashTable
- 如何把一个线程不安全的集合类变成一个线程安全的集合类
用Collections工具类的方法即可
List<String> list2 = Collections.synchronizedList(new ArrayList<String>()); // 线程安全
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();
}
}