1:死锁:
synchronized在开发中最好不要嵌套使用,可能导致死锁。
public class SiSuo01 {
public static void main(String[] args) {
//将o1和o2new出来
Object o1 = new Object();
Object o2 = new Object();
//将o1和o2传给线程,t1t2共享o1o12
Thread t1 = new MyThread1(o1,o2);
Thread t2 = new MyThread2(o1,o2);
//创建线程
t1.start();
t2.start();
}
}
class MyThread1 extends Thread{
Object o1;
Object o2;
public MyThread1(Object o1,Object o2){
this.o1 = o1;
this.o2 = o2;
}
public void run() {
synchronized (o1){
//如果添加sleep方法
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2){
}
}
}
}
class MyThread2 extends Thread {
Object o1;
Object o2;
public MyThread2(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
@Override
public void run() {
synchronized (o2){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1){
}
}
}
}
2:开发中应该怎么解决线程安全问题?
2.1:是不是一上来就使用线程同步?synchronized
并不是,synchronized会让执行效率降低,用户体验降低,系统的用户吞吐量降低(并发性),不得已使用synchronized。
2.2: 经量将局部变量代替实例变量,静态变量。
2.3:如果必须使用实例变量,那么可以创建多个对象,这样内存就不会共享(一个线程对应一个对象,100个线程对应100个对象对象不共享,就没有线程安全问题!!)
2.4:如果不能使用局部变量,对象也不能创建多个,这个时候使用synchronized,线程同步机制。
3:守护线程:
3.1:java语言线程分为两大类:
一类:用户线程
一类:守护线程
其中最具代表性是:垃圾回收机制(守护线程)。
3.2:守护线程特点:
一般守护线程是一个死循环,所以用户线程只有一结束,守护线程自动结束。
注:主线程main方法是一个用户线程
3.3:守护线程用在什么地方?
每天零点时候系统数据自动备份。
这个时候使用定时器,我们可以将定时器设置守护线程。
3.4:守护线程代码实现!!!!!!!!!!
publicclassShoHuXianCheng {
publicstaticvoidmain(String[] args) {
//将线程new出来
Threadt=newMyThread3();
t.setName("备份线程");
//启动线程的时候:将线程设置为守护线程
t.setDaemon(true);
t.start();
//主线程:主线程是一个用户线程
for (inti=0; i<10; i++) {
System.out.println(Thread.currentThread().getName()+"---->"+i);
try {
Thread.sleep(1000);
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
}
}
classMyThread3extendsThread{
@Override
publicvoidrun() {
inti=0;
//定义一个死循环
while (true){
System.out.println(Thread.currentThread().getName()+"--->"+(++i));
try {
Thread.sleep(1000);
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
}
}
4:定时器:
4.1作用:
间隔特定的时间,执行特定的程序!!
4.2:概述:
数据备份,在实际开发中,每隔多久执行一段特定程序。
可以使用sleep设置但太low了,在java类库中java.util.Timer,高级框架都支持。
使用较多spring框架中提供SpringTask框架
4.3:定时器的实现;
publicclassDingShiQi {
publicstaticvoidmain(String[] args) throwsParseException {
//创建一个定时器
Timertimer=newTimer();
//Timer timer = new Timer(trun);(守护线程方式)
//指定定时方式
//timer.schedule(定时任务,第一次执行时间,间隔多久执行一次);
SimpleDateFormatsdf = newSimpleDateFormat("yyyy-MM-dd HH-mm-ss SSS") ;
DatefirstTime= sdf.parse("2021-04-15 10:18:04");//将字符串转换为数字
// timer.schedule(new logTimerTask(),firstTime,period);
timer.schedule(newLogTimerTask(),firstTime, 1000);
}
}
classLogTimerTaskextendsTimerTask{
@Override
publicvoidrun() {
SimpleDateFormatsdf = newSimpleDateFormat("yyyy-MM-dd HH-mm-ss SSS") ;
Stringstr=sdf.format(newDate());
System.out.println(str+"成功完成一次数据备份!");
}
}
5:实现线程的第三种方法:实现Callable接口
5.1:优点:可以取得线程的执行结果
缺点:效率低,在获取线程执行结果时,当前线程阻塞,效率低。
5.2:代码实现:
importjava.util.concurrent.Callable;
importjava.util.concurrent.ExecutionException;
importjava.util.concurrent.FutureTask;
publicclassThreadTest15 {
publicstaticvoidmain(String[] args) throwsExecutionException, InterruptedException {
//第一步:创建一个“未来任务类”对象
FutureTasktask=newFutureTask(newCallable() {
@Override
publicObjectcall() throwsException { //call()方法相当于run方法,只不过这个有返回值
//线程执行一个任务,执行之后会有一个结果
System.out.println("begin");
Thread.sleep(1000);
System.out.println("end");
inta=100;
intb=200;
returna-b; //自动装箱
}
});
//创建线程对象
Threadt=newThread(task);
//启动线程
t.start();
//这里是main方法,主线程
//怎么获取
//get()方法执行导致“当前线程堵塞”一直getget只有等到主线程结束才行
Objectobj=task.get();
System.out.println("牛啊"+obj);
System.out.println("l");
}
}
6:关于Object类中wait和notify方法。(生产者和消费者模式!)
6.1:wait和notify方法不是线程对象方法,是java任何一个java对象都有的方法,因为这是Object中自带的
wait和notify不是通过线程对象调用,不是t.wait或者t.notify
wait作用?
Object o = new Object();
o.wait();
表示:让o对象上活动的线程进入1等待状态,无期限等待。o.wait()方法使线程进入等待状态!!
notify作用:唤醒被0.wait()使睡觉的方法。
Object o = new Object();
o.notify(),还有一个notifyAll()方法,唤醒所以等待线程!!
7.生产者与消费者代码实现!!!
packagecom.bjpowernode.java.threadsafe;
importjava.awt.*;
importjava.util.ArrayList;
importjava.util.List;
publicclassWiatDanNotify {
publicstaticvoidmain(String[] args) {
//创建一个仓库对象
Listlist=newArrayList();
//创建两个线程对象
//生产线程
Threadt1=newThread(newProducer(list));
//消费者线程
Threadt2=newThread(newConsumer(list));
t1.setName("生产线程");
t2.setName("消费线程");
t1.start();
t2.start();
}
}
//上产线程
classProducerimplementsRunnable{
//仓库
privateListlist;
publicProducer(Listlist){
this.list=list;
}
@Override
publicvoidrun() {
//一直生产
while (true){
synchronized (list){
if (list.size() >0) {
try {
list.wait();
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
//程序能够运行到这说明仓库空了,可以生产
Objectobj=newObject();
list.add(obj);
System.out.println(Thread.currentThread().getName()+"-->"+obj);
//唤醒消费者进行消费
list.notifyAll();
}
}
}
}
classConsumerimplementsRunnable{
//仓库
privateListlist;
publicConsumer(Listlist){
this.list=list;
}
@Override
publicvoidrun() {
//一直生产
while (true){
//一直消费
synchronized (list){
if (list.size() ==0) {
try {
list.wait();
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
//程序能够运行到这说明仓库有数据,可以消费
Objectobj=list.remove(0);
list.add(obj);
System.out.println(Thread.currentThread().getName()+"-->"+obj);
//唤醒消费者进行生产
list.notifyAll();
}
}
}
}
//消费线程
7.1:使用wait方法和notify方法实现”生产者和消费者模式“。
7.2:什么是“生产者和消费者模式”?
生产者负责生产,消费者负责消费;
生产线程和消费线程达到均衡;
特殊情况使用wait和notify。
7.3:wait和notify不是线程对象方法,是普通java对象都有方法
7.4:建立在同步基础之上,因为多线程要用时操作一个仓库
7.5:作用:让o对象线程进入等待状态,并且释放对象锁。o.notify让等待线程唤醒。