一、产生线程安全的原因
(1)多个线程在操作共享数据
(2)操作共享数据的线程代码有多条
结论:当一个线程在执行操作共享数据的多条代码过程中,其他线程参与运算,就会导致线程安全问题的产生。
二、解决方案:同步锁,同步锁分为两种如下:
(1)同步锁代码块
Synchronized(对象){
//code;
}
(2)同歩锁函数
public synchronized void show(){
//code;
}
同步锁函数和同步代码块的区别:
①同步函数的锁是固定的this;
②同步代码块的锁是任意的对象;
③静态的同步函数使用的锁是该函数所属字节码文件对象,可以用getClass()方法获取,也可以用当前类名.class获取;
(3)使用同歩锁的前提:必须有多个线程并同时使用同一个锁;三、死锁原因
(1)同步锁嵌套
synchronized(MyLocked.locka){
System.out.println(Thread.currentThread().getName()+" if locka....");
synchronized(MyLocked.lockb){
System.out.println(Thread.currentThread().getName()+" if lockb....");
}
}
(2)线程间的通讯,多个线程在处理同一个资源,但任务却不同
//资源
class Resource
{
String name;
String sex;
}
//输入
class Input implements Runnable
{
Resource r ;
// Object obj = new Object();
Input(Resource r)
{
this.r = r;
}
public void run()
{
int x = 0;
while(true)
{
synchronized(r)
{
if(x==0)
{
r.name = "mike";
r.sex = "nan";
}
else
{
r.name = "丽丽";
r.sex = "女女女女女女";
}
}
x = (x+1)%2;
}
}
}
//输出
class Output implements Runnable
{
Resource r;
// Object obj = new Object();
Output(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
synchronized(r)
{
System.out.println(r.name+"....."+r.sex);
}
}
}
}
class ResourceDemo
{
public static void main(String[] args)
{
//创建资源。
Resource r = new Resource();
//创建任务。
Input in = new Input(r);
Output out = new Output(r);
//创建线程,执行路径。
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
//开启线程
t1.start();
t2.start();
}
}
四、等待/唤醒机制
(1)wait();让线程处于冻结状态,被wait的线程会被存储到线程池中;
(2)notify();唤醒线程池中一个线程(任意);
(3)notifyAll();唤醒线程池中的所有线程;
总结:这些方法都必须能定义在同步锁中,因为这些方法是用于操作线程状态的方法,必须能要明确到底操作的是哪个锁上的线程
为什么操作线程的方法wait notify notifyAll定义在了Object类中?
因为这些方法是监视器的方法。监视器其实就是锁。锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。
五、示例如下:
资源类:
package com.edu.csu.syn;
public class Resource {
private String name;
private String sex;
private boolean flag = false;
public synchronized void set(String name,String sex){
if(flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out(){
if(!flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+"......"+sex);
flag = false;
this.notify();
}
}
输入类:
package com.edu.csu.syn;
public class Input implements Runnable {
private Resource r;
public Input(Resource r){
this.r = r;
}
@Override
public void run() {
int x = 0;
while(true){
if (x == 0) {
r.set("mike", "nan");
} else {
r.set("丽丽", "女女女女");
}
x = (x + 1) % 2;
}
}
}
输出类:
package com.edu.csu.syn;
public class Output implements Runnable {
private Resource r;
public Output(Resource r){
this.r = r;
}
@Override
public void run() {
while(true){
r.out();
}
}
}
测试类:
package com.edu.csu.syn;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
//创建资源
Resource r = new Resource();
//创建任务
Input i = new Input(r);
Output o = new Output(r);
//创建线程,执行任务
Thread t = new Thread(i);
Thread t1 = new Thread(o);
//开启线程
t.start();
t1.start();
}
}