java锁与同步基础入门.docx
《java锁与同步基础入门.docx》由会员分享,可在线阅读,更多相关《java锁与同步基础入门.docx(16页珍藏版)》请在冰豆网上搜索。
java锁与同步基础入门
1同步
SellTiclet.java
packagecn.itcast_01;
importjava.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
publicclassSellTicketimplementsRunnable{
//定义票
privateinttickets=100;
//定义锁对象
privateLocklock=newReentrantLock();
@Override
publicvoidrun(){
while(true){
try{
//加锁
lock.lock();
if(tickets>0){
try{
Thread.sleep(100);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+"正在出售第"+(tickets--)+"张票");
}
}finally{
//释放锁
lock.unlock();
}
}
}
}
SellTicketDemo.java
packagecn.itcast_01;
/*
*虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,
*为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。
*
*Lock:
*voidlock():
获取锁。
*voidunlock():
释放锁。
*ReentrantLock是Lock的实现类.
*/
publicclassSellTicketDemo{
publicstaticvoidmain(String[]args){
//创建资源对象
SellTicketst=newSellTicket();
//创建三个窗口
Threadt1=newThread(st,"窗口1");
Threadt2=newThread(st,"窗口2");
Threadt3=newThread(st,"窗口3");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
2同步的弊端
DieLock.java
packagecn.itcast_02;
publicclassDieLockextendsThread{
privatebooleanflag;
publicDieLock(booleanflag){
this.flag=flag;
}
@Override
publicvoidrun(){
if(flag){
synchronized(MyLock.objA){
System.out.println("ifobjA");
synchronized(MyLock.objB){
System.out.println("ifobjB");
}
}
}else{
synchronized(MyLock.objB){
System.out.println("elseobjB");
synchronized(MyLock.objA){
System.out.println("elseobjA");
}
}
}
}
}
DieLockDome.java
packagecn.itcast_02;
/*
*同步的弊端:
*A:
效率低
*B:
容易产生死锁
*
*死锁:
*两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。
*
*举例:
*中国人,美国人吃饭案例。
*正常情况:
*中国人:
筷子两支
*美国人:
刀和叉
*现在:
*中国人:
筷子1支,刀一把
*美国人:
筷子1支,叉一把
*/
publicclassDieLockDemo{
publicstaticvoidmain(String[]args){
DieLockdl1=newDieLock(true);
DieLockdl2=newDieLock(false);
dl1.start();
dl2.start();
}
}
MyLock.java
packagecn.itcast_02;
publicclassMyLock{
//创建两把锁对象
publicstaticfinalObjectobjA=newObject();
publicstaticfinalObjectobjB=newObject();
}
3资源类
GetThread.java
packagecn.itcast_03;
publicclassGetThreadimplementsRunnable{
privateStudents;
publicGetThread(Students){
this.s=s;
}
@Override
publicvoidrun(){
//Students=newStudent();
System.out.println(s.name+"---"+s.age);
}
}
SetThread.java
packagecn.itcast_03;
publicclassSetThreadimplementsRunnable{
privateStudents;
publicSetThread(Students){
this.s=s;
}
@Override
publicvoidrun(){
//Students=newStudent();
s.name="林青霞";
s.age=27;
}
}
Student,java
packagecn.itcast_03;
publicclassStudent{
Stringname;
intage;
}
StudentDemo.java
packagecn.itcast_03;
/*
*分析:
*资源类:
Student
*设置学生数据:
SetThread(生产者)
*获取学生数据:
GetThread(消费者)
*测试类:
StudentDemo
*
*问题1:
按照思路写代码,发现数据每次都是:
null---0
*原因:
我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
*如何实现呢?
*在外界把这个数据创建出来,通过构造方法传递给其他的类。
*
*/
publicclassStudentDemo{
publicstaticvoidmain(String[]args){
//创建资源
Students=newStudent();
//设置和获取的类
SetThreadst=newSetThread(s);
GetThreadgt=newGetThread(s);
//线程类
Threadt1=newThread(st);
Threadt2=newThread(gt);
//启动线程
t1.start();
t2.start();
}
}
4序列流
GetThread.java
packagecn.itcast_04;
publicclassGetThreadimplementsRunnable{
privateStudents;
publicGetThread(Students){
this.s=s;
}
@Override
publicvoidrun(){
while(true){
synchronized(s){
System.out.println(s.name+"---"+s.age);
}
}
}
}
SetThread.java
packagecn.itcast_04;
publicclassSetThreadimplementsRunnable{
privateStudents;
privateintx=0;
publicSetThread(Students){
this.s=s;
}
@Override
publicvoidrun(){
while(true){
synchronized(s){
if(x%2==0){
s.name="林青霞";//刚走到这里,就被别人抢到了执行权
s.age=27;
}else{
s.name="刘意";//刚走到这里,就被别人抢到了执行权
s.age=30;
}
x++;
}
}
}
}
Student.java
packagecn.itcast_04;
publicclassStudent{
Stringname;
intage;
}
StudentDemo.java
packagecn.itcast_04;
/*
*分析:
*资源类:
Student
*设置学生数据:
SetThread(生产者)
*获取学生数据:
GetThread(消费者)
*测试类:
StudentDemo
*
*问题1:
按照思路写代码,发现数据每次都是:
null---0
*原因:
我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
*如何实现呢?
*在外界把这个数据创建出来,通过构造方法传递给其他的类。
*
*问题2:
为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
*A:
同一个数据出现多次
*B:
姓名和年龄不匹配
*原因:
*A:
同一个数据出现多次
*CPU的一点点时间片的执行权,就足够你执行很多次。
*B:
姓名和年龄不匹配
*线程运行的随机性
*线程安全问题:
*A:
是否是多线程环境是
*B:
是否有共享数据是
*C:
是否有多条语句操作共享数据是
*解决方案:
*加锁。
*注意:
*A:
不同种类的线程都要加锁。
*B:
不同种类的线程加的锁必须是同一把。
*/
publicclassStudentDemo{
publicstaticvoidmain(String[]args){
//创建资源
Students=newStudent();
//设置和获取的类
SetThreadst=newSetThread(s);
GetThreadgt=newGetThread(s);
//线程类
Threadt1=newThread(st);
Threadt2=newThread(gt);
//启动线程
t1.start();
t2.start();
}
}
5线程运行
GetThread.java
packagecn.itcast_05;
/*
*分析:
*资源类:
Student
*设置学生数据:
SetThread(生产者)
*获取学生数据:
GetThread(消费者)
*测试类:
StudentDemo
*
*问题1:
按照思路写代码,发现数据每次都是:
null---0
*原因:
我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
*如何实现呢?
*在外界把这个数据创建出来,通过构造方法传递给其他的类。
*
*问题2:
为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
*A:
同一个数据出现多次
*B:
姓名和年龄不匹配
*原因:
*A:
同一个数据出现多次
*CPU的一点点时间片的执行权,就足够你执行很多次。
*B:
姓名和年龄不匹配
*线程运行的随机性
*线程安全问题:
*A:
是否是多线程环境是
*B:
是否有共享数据是
*C:
是否有多条语句操作共享数据是
*解决方案:
*加锁。
*注意:
*A:
不同种类的线程都要加锁。
*B:
不同种类的线程加的锁必须是同一把。
*
*问题3:
虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
*如何实现呢?
*通过Java提供的等待唤醒机制解决。
*
*等待唤醒:
*Object类中提供了三个方法:
*wait():
等待
*notify():
唤醒单个线程
*notifyAll():
唤醒所有线程
*为什么这些方法不定义在Thread类中呢?
*这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
*所以,这些方法必须定义在Object类中。
*/
publicclassStudentDemo{
publicstaticvoidmain(String[]args){
//创建资源
Students=newStudent();
//设置和获取的类
SetThreadst=newSetThread(s);
GetThreadgt=newGetThread(s);
//线程类
Threadt1=newThread(st);
Threadt2=newThread(gt);
//启动线程
t1.start();
t2.start();
}
}
SetThread.java
packagecn.itcast_05;
publicclassSetThreadimplementsRunnable{
privateStudents;
privateintx=0;
publicSetThread(Students){
this.s=s;
}
@Override
publicvoidrun(){
while(true){
synchronized(s){
//判断有没有
if(s.flag){
try{
s.wait();//t1等着,释放锁
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
if(x%2==0){
s.name="林青霞";
s.age=27;
}else{
s.name="刘意";
s.age=30;
}
x++;//x=1
//修改标记
s.flag=true;
//唤醒线程
s.notify();//唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。
}
//t1有,或者t2有
}
}
}
Student.java
packagecn.itcast_05;
publicclassStudent{
Stringname;
intage;
booleanflag;//默认情况是没有数据,如果是true,说明有数据
}
StudentDemo.java
packagecn.itcast_05;
/*
*分析:
*资源类:
Student
*设置学生数据:
SetThread(生产者)
*获取学生数据:
GetThread(消费者)
*测试类:
StudentDemo
*
*问题1:
按照思路写代码,发现数据每次都是:
null---0
*原因:
我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
*如何实现呢?
*在外界把这个数据创建出来,通过构造方法传递给其他的类。
*
*问题2:
为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
*A:
同一个数据出现多次
*B:
姓名和年龄不匹配
*原因:
*A:
同一个数据出现多次
*CPU的一点点时间片的执行权,就足够你执行很多次。
*B:
姓名和年龄不匹配
*线程运行的随机性
*线程安全问题:
*A:
是否是多线程环境是
*B:
是否有共享数据是
*C:
是否有多条语句操作共享数据是
*解决方案:
*加锁。
*注意:
*A:
不同种类的线程都要加锁。
*B:
不同种类的线程加的锁必须是同一把。
*
*问题3:
虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
*如何实现呢?
*通过Java提供的等待唤醒机制解决。
*
*等待唤醒:
*Object类中提供了三个方法:
*wait():
等待
*notify():
唤醒单个线程
*notifyAll():
唤醒所有线程
*为什么这些方法不定义在Thread类中呢?
*这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
*所以,这些方法必须定义在Object类中。
*/
publicclassStudentDemo{
publicstaticvoidmain(String[]args){
//创建资源
Students=newStudent();
//设置和获取的类
SetThreadst=newSetThread(s);
GetThreadgt=newGetThread(s);
//线程类
Threadt1=newThread(st);
Threadt2=newThread(gt);
//启动线程
t1.start();
t2.start();
}
}
6