1。设置线程名
继承Thread类的线程,可以直接使用.setName()方法,设置线程名。也可以使用构造方法,需要注意java默认不继承构造方法,所以需要自己调用下父类的构造方法。
public class Demo {
public static void main(String[] args) {
MyThread myThread1=new MyThread("飞机");
myThread1.start();
MyThread myThread2=new MyThread();
myThread2.setName("火箭");
myThread2.start();
//当jvm虚拟机启动后,会自动的启动多条线程,其中一条是main主线程
//主线程的作用是调用main方法,并执行其中的代码,在以前,我们写的所有代码,其实都是运行在main线程中
Thread thread=Thread.currentThread();
System.out.println(thread.getName());
//获取优先级
System.out.println(myThread1.getPriority());
//线程的默认优先级都是5,包括main线程
}
}
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; ++i) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//在不设置线程名的情况下,线程名默认是Thread+线程序号
System.out.println(getName());
}
}
//构造方法子类默认不继承,所以这里需要通过super关键字调用父类Thread的构造方法,给Thread设置名字
public MyThread() {
}
public MyThread(String name) {
super(name);
}
}
实现runnable接口的线程,可以使用.setName方法。但是不能使用构造方法,因为他不像上面继承Thread类的线程,他没有父类的构造方法可以调用。
public class Mythread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; ++i) {
String name = Thread.currentThread().getName();
System.out.println("你好世界!"+"----"+name);
}
}
}
public class Demo {
public static void main(String[] args) {
Mythread mythread=new Mythread();
Thread t1=new Thread(mythread);
t1.setName("线程1");
Thread t2=new Thread(mythread);
t2.setName("线程2");
t1.start();
t2.start();
//获取优先级
System.out.println(t1.getPriority());
}
}
2. join方法 当前线程需要等待 调用join方法的线程执行完毕,当前线程才能继续执行
public class Demo {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.start();
// 在默认情况下,当前线程和在当前线程添加的线程会交替执行
// 使用了join方法后,当前线程会等待myThread执行完毕,后继续执行本线程
myThread.join();
for (int i = 0; i < 10; i++) {
Thread.sleep(1);//模拟主线程执行耗时
System.out.println(Thread.currentThread().getName());
}
}
}
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; ++i) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("自定义线程"+i);
}
}
}
执行结果:MyThread执行完后,才执行main线程的输出语句
3。
setDaemon
守护线程:当其他非守护线程执行完毕,守护线程不管是否执行完毕,都会停止。
就像舔狗(守护线程)和女神(非守护线程),如果女神走了,那舔狗啥都不管,也走。
主线程
public class Demo {
public static void main(String[] args) {
NvShenThread nvShenThread=new NvShenThread();
TianGouThread tianGouThread =new TianGouThread();
//将舔狗线程设置为守护线程 守护线程:当其他非守护线程执行完毕,会自动停止守护线程
//应用场景:qq聊天和发送文件,聊天框关闭,发送文件也应当停止
tianGouThread.setDaemon(true);
nvShenThread.start();
tianGouThread.start();
}
}
女神线程(非守护线程)
public class NvShenThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("女神线程执行"+"----"+i);
}
}
}
舔狗线程(守护线程)
public class TianGouThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("舔狗线程执行"+"----"+i);
}
}
}
同步代码块
synchronized (锁对象){
}
1.锁默认打开,有一个线程进去,锁默认关闭
2.同一时间只有一个线程能获取到锁对象,并执行其中的代码
锁对象要用static修饰,以确保不同对象获取到的是一把锁,否则不同线程获取到的是不同的锁,锁会失效
同步方法:
把synchronized直接加到方法上,锁对象不能自己制定,是java默认规定好的:如果是非静态方法 ,锁对象是this 。如果是静态方法,锁对象是当前类的字节码文件
lock :
比synchronized更灵活,可以手动加锁和手动释放锁
等待唤醒机制
目的:线程的执行有随机性,实现两个线程轮流执行
生产者等待 :消费者: 1.没有食物,吃货等待。
2.有食物,开吃
3.吃完后唤醒厨师继续做
生产者:1.有食物,生产者等待。
2.没有,制作食物
3.叫醒吃货开吃。
notify 随机唤醒一个线程
notifyAll 唤醒所有线程
.wait()方法相当于放弃了这次获取cpu的执行权,将当前线程设置为等待状态。同时释放锁。
阻塞队列方式
阻塞队列,好像是生产者和消费者之间的管道。可以规定管道的长度。
生产者往管道中放数据时(put)如果队列已经满了,生产者会等待,也叫做阻塞
消费者从管道中拿数据时(take)如果队列为空,获取不到数据,消费者会等待,也叫做阻塞。
生产者和消费者必须使用同一个消费队列!!!
线程复用:
重复利用已经创建的线程来执行多个任务,而不是为每一个任务都新建一个线程。
需要用到线程池。