一、线程
1、守护线程’setDaemon(true);
意思就是当这个java程序子线程或者子线程停止了,守护线程接收到了这个消息,就会马上让守护线程终止,但是守护线程还是会继续执行一下,可以理解为自杀也需要一点时间。
ThreadDaemon td1 = new ThreadDaemon();
ThreadDaemon td2 = new ThreadDaemon();
td1.setName("关羽");
td2.setName("张飞");
// 设置守护线程
td1.setDaemon(true);
td2.setDaemon(true);
td1.start();
td2.start();
设置当前main线程为刘备,并且循环5次,让线程能继续走一下。
Thread.currentThread().setName("刘备");
for (int x = 0; x < 5; x++) {
System.out.println(Thread.currentThread().getName() + ":" + x);
}
2、线程加入 join
ThreadJoin tj1 = new ThreadJoin();
ThreadJoin tj2 = new ThreadJoin();
ThreadJoin tj3 = new ThreadJoin();
tj1.setName("李渊");
tj2.setName("李世民");
tj3.setName("李元霸");
tj1.start();
try {
//在启动之后设置join。等待该线程执行完毕,其余线程才能继续执行。
tj1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
tj2.start();
tj3.start();
for (int x = 0; x < 100; x++) {
System.out.println("main" + x);
}
3、线程优先级
1-10,默认5 ,但是只是几率设置的高了一点,不是绝对的
方法 tp1.setPriority(10);
tp2.setPriority(1);
4、线程休眠
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(getName() + ":" + x + ",日期:" + new Date());
// 睡眠
// 困了,我稍微休息1秒钟
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
5、中断线程 interrupt
ThreadStop ts = new ThreadStop();
ts.start();
try {
//主线程休眠3秒
Thread.sleep(3000);
// ts.stop();
//中断线程,并且该线程继续往后执行,并且抛出异常InterruptedException
ts.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
public class ThreadStop extends Thread {
@Override
public void run() {
System.out.println("开始执行:" + new Date());
// 我要休息10秒钟,亲,不要打扰我哦
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("线程被终止了");
}
//使用interrupt之后的代码也会执行,但是stop就不会执行了。
for(int i = 0 ; i < 50000 ;i++) {
System.out.println("结束执行:" + new Date());
}
}
}
6、线程礼让
/*
* public static void yield():暂停当前正在执行的线程对象,并执行其他线程。
* 让多个线程的执行更和谐,但是不能靠它保证一人一次。
*/
public class ThreadYieldDemo {
public static void main(String[] args) {
ThreadYield ty1 = new ThreadYield();
ty1.setName("林青霞");
new Thread() {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(getName() + ":" + x);
}
};
}.start();
ty1线程中run方法有yield礼让,所以之前的线程基本会先执行完
ty1.start();
}
}
礼让
public class ThreadYield extends Thread {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(getName() + ":" + x);
Thread.yield();
}
}
}
二、线程的生命周期
三、创建线程的另外一种形式,使用Runnable接口
public class MyRunnableDemo {
public static void main(String[] args) {
//创建完成接口runnable的对象
MyRunnable myRunnable = new MyRunnable();
//创建线程把Runnable对象放入thread线程里,这个时候这个线程的run就是这个Runnable中的run了
Thread thread = new Thread(myRunnable);
Thread thread2 = new Thread(myRunnable,"欧文");
thread2.start();
thread.start();
}
}
实现Runnable接口
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
四、 继承Thread和实现Runnable接口区别:
1.继承有局限性,如果多个线程使用一个线程类容就需要使用静态数据来共享数据。
2.接口适合扩展:可以创建一个接口用来构造多个线程。构造的线程类容出去Run中的数据共享,也不需要静态。
五、同步锁
1 、买票,不加同步锁问题
if (number > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第: " + (number--) + " 张票");
}
多个线程执行同一个run方法。判断条件三个线程都能进来。然后都减一了,最后出现0,-1情况
2、解决这样的问题只需要加同步锁:
加锁需要对象,即是一把锁。 这种包起来的锁,可以为任意对象,但是多个线程应该持有一把锁,而不是都用自己的锁。所以应该改为:synchronized(obj)
synchronized (new Object()) {
if (number > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第: " + (number--) + " 张票");
}
}
3、同步锁可以直接包方法。
public synchronized void SellTick()
但是包了之后想与其他的锁使用同一把锁就不能再使用任何对象了,而是this才可以了
4、同步锁包静态方法
public static synchronized void SellTick()
要和静态方法使用同一把锁是字节码文件。类名.class
分析:
Person p = new Person();
创建对象时候先把字节码文件放入内存,但是静态数据是随着类的加载而加载,这个时候对象也没创建自然不可能是this。所以设置为字节码文件。类名,class
六、死锁
private boolean flag;
//传入一个true和false
public DieLock(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
//if就分别执行两个
MyLock.objA 是一个静态属性Object对象
MyLock.objB 是一个静态属性Object对象
两个线程同时进入,第一个到了ifObjA,第二个线程就到了else ObjeB。这时候B上锁了,线程一就无法走了,线程二也无法获取A了
if(flag) {
synchronized (MyLock.objA) {
System.out.println("if ObjA");
synchronized (MyLock.objB) {
System.out.println("if ObjB");
}
}
}else {
synchronized (MyLock.objB) {
System.out.println("else ObjB");
synchronized (MyLock.objA) {
System.out.println("else ObjA");
}
}
七、等待和唤醒
操作思想:
1、发送数据,如果没有接收就等着,接收了之后才再次发送数据。
2、接收数据,如果没有发送数据就等着,有了数据就接收。
发送数据
@Override
public void run() {
while(true) {
synchronized(s) {
//判断是否有值
if(s.flag) {
//有值就等待另外的来获取,不在生产。
try {
s.wait(); //等待时候会释放锁,再次被唤醒的时候也是这个位置,
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(x%2==0) {
s.name="小兰";
s.age = 17;
}else {
s.name="新一";
s.age = 18;
}
x++;
//设置为有值
s.flag = true;
s.notify(); //将等待的s唤醒 但是还需要抢cpu执行权,如果没wait等待就是相当于没有
}
}
接收数据
@Override
public void run() {
while(true) {
synchronized (s) {
if(!s.flag) {
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有值就打印
System.out.println(s.name+"--"+s.age);
s.flag = false;
s.notify(); //唤醒
}
}
八、优化
public class Student {
private String name;
private int age;
private boolean flag;
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;
flag = true;
this.notify();
}
public synchronized void get() {
if(!this.flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name+"--"+age);
flag = false;
this.notify();
}
}