package com.zhou.SynchronizationOfThread;
/**
* 线程的同步:
* 问题:通过多线程解决小朋友分苹果的问题,一共有5个苹果,2个小朋友同时拿苹果,每次拿一个,拿完为止;
* --小明小朋友拿走了一个苹果,还剩4个苹果;
* --小强小朋友拿走了一个苹果,还剩3个苹果;
* --小明小朋友拿走了一个苹果,还剩2个苹果;
* --小强小朋友拿走了一个苹果,还剩1个苹果;
* --小明小朋友拿走了一个苹果,还剩0个苹果;
* 小强的线程进入死亡状态;
* 小明的线程进入死亡状态;
*
* 线程安全:
* 1.理解并编写出线程不安全的实例代码;
* 多线程应用程序同时访问共享对象时,由于线程间相互抢占Cpu的控制权,造成一
* 个线程夹在另一个线程的执行过程中运行,所以可能导致错误的执行结果;
* 2.使用synchronized (锁住共享的资源){}代码块来解决线程安全的问题;
* ---注意:需要在synchronized代码块中参照共同的一个对象,
* 也就是锁的就是共享资源,因为是多个线程在访问共享资源时
* 出现线程安全的问题;
* synchronized关键字:
* 为了防止共享资源在并发访问时出现错误,Java中提供了”synchronized“关键字;
* synchronized关键字确保共享对象在同一时刻只只能被一个线程访问,这种处理机制称作为”线程同步“或”线程互斥“;
* Java中的”线程同步“基于”对象锁“的概念;
* 使用synchronized关键字:
* 1.修饰方法:被”synchronized“关键字修饰的方法称为”同步方法“;
* //定义同步方法;
* public synchronized void methodName(){方法实体}
* 2.当一个线程访问对象的同步方法时,被访问对象就处于”锁定状态“,访问该方法的其他线程只能等待,
* 对象中的其他同步方法也不能访问,但非同步方法则可以访问;
* 3.可以使用synchronized关键字修饰部分代码,如果只希望同步部分代码行,可以使用”同步块“;
* // 同步块;
* synchronized(obj){//被同步的代码块}
* 同步块的作用与同步方法一样,只是控制范围有所区别;
*
*
*
*
* 如何解决线程安全的问题?
* 加锁,多个线程用一把锁;
*
* @author Administrator
*
*/
public class
ShareApple implements Runnable{
//这个时候两个线程用一个资源,所以使用Runnable接口;
//一共有5个苹果;
private int appleCount = 5;
//两个小朋友来拿苹果,写一个方法;
boolean getApple(){
//怎样来给线程加锁呢,前提条件是有一个共享的对象,这里的这个ShareApple就是一个共享的对象;
synchronized (this) {
//锁住这个共享的资源,如果ShareApple这个共享的资源被抢去了,我就拿这个共享资源来作为参照;
//来写如何取苹果;
if(appleCount > 0){
//只要有,我就拿;
//拿走了一个之后,总的苹果数少一个;
appleCount --;
//现在我人工的让它出现线程安全的问题;
try {
Thread.sleep(1000);
//我让它停1秒钟;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//拿了苹果之后,我还要显示下还剩多少个苹果;
System.out.println(Thread.currentThread().getName() + "拿走了一个苹果。" + "还剩" + appleCount + "个苹果。");
//总的苹果数还大于0,也就是还有苹果没被拿完,就返回的是true;
return true;
}
return false;
}
}
//线程体;
@Override
public void run() {
//写个那苹果的标志;
boolean flag = getApple();
//首先取一下,看有没有苹果;
while(flag){
//只要有苹果的话我就取;
flag = getApple();
}
//要是没有苹果的话,就提示苹果被拿完了;
System.out.println("苹果被拿完了!"+Thread.currentThread().getName()+"-线程结束");
}
//测试的main方法;
public static void main(String[] args) {
// 创建以后实现了Runnable接口的实现类的对象;
ShareApple shareApple = new ShareApple();
//创建并启动两个线程;
Thread thread1 = new Thread(shareApple);
Thread thread2 = new Thread(shareApple);
//给线程起名字;
thread1.setName("小明");
thread2.setName("小强");
//启动线程;
thread1.start();
thread2.start();
}
}
package com.zhou.SynchronizationOfThread;
public class
PrintLetters implements Runnable{
//写一个共用的char;
private char c = 'a';
//然后写一个打印;
public synchronized boolean print(){
//只要小于z的话就可以打印;
//synchronized (this) {
if(c <= 'z'){
System.out.println(Thread.currentThread().getName() + ":" + c);
//这个中间我可以加一个锁;
//现在我要模拟出线程安全的问题,在这里让线程睡眠1秒再打印;
try {
Thread.currentThread().sleep(1000);
//睡眠1秒再打印;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//打印完之后我应该是向前走一个;
c++;
return true;
//可以打印
}
return false;
//否则不可以打印;
//}
}
@Override
public void run() {
//执行
boolean flag = print();
while(flag){
//只要flag为true的话
flag = print();
//我就接着打印;
}
}
//测试的main方法;
public static void main(String[] args) {
//我要两线程一千打印;
//创建一个实现了Runnable接口的实现类对象;
PrintLetters printLetters = new PrintLetters();
//创建两个线程;
Thread thread1 = new Thread(printLetters);
Thread thread2 = new Thread(printLetters);
//给线程起名字;
thread1.setName("线程-1");
thread2.setName("线程-2");
//启动线程;
thread1.start();
thread2.start();
}
}
本文出自 “IT技术JAVA” 博客,转载请与作者联系!