1.线程安全概念:当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类就是线程安全的。
synchronized:可以在任意对象及方法上加锁,而枷锁的这段代码成为“互斥区”或临界区。
package com.cn.test;
public class MyThread extends Thread{
private int count =5;
public void run(){
count--;
System.out.println(this.currentThread().getName()+" count="+count);
}
public static void main(String[] args){
MyThread a=new MyThread();
Thread t1=new Thread(a,"t1");
Thread t2=new Thread(a,"t2");
Thread t3=new Thread(a,"t3");
Thread t4=new Thread(a,"t4");
Thread t5=new Thread(a,"t5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
输出结果:
t1 count=3
t5 count=1
t4 count=2
t2 count=3
t3 count=0
使用stnchronized:
package com.cn.test;
public class MyThread extends Thread{
private int count =5;
public synchronized void run(){
count--;
System.out.println(this.currentThread().getName()+" count="+count);
}
public static void main(String[] args){
MyThread a=new MyThread();
Thread t1=new Thread(a,"t1");
Thread t2=new Thread(a,"t2");
Thread t3=new Thread(a,"t3");
Thread t4=new Thread(a,"t4");
Thread t5=new Thread(a,"t5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
输出结果:
t1 count=4
t3 count=3
t2 count=2
t5 count=1
t4 count=0
当多个线程访问myThread main方法时,以排队的方式进行处理(这里排队事按照cpu分配的先后顺序而定的),一个线程想要执行synchronized修饰的方法丽的代码,首先事 尝试获得锁,如果拿到锁,执行synchronized代码内容;拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,而且是多个线程同时去竞争这把锁(也就是会有锁竞争的问题)
2.多个线程多个锁:多个线程,每个线程都可以拿到自己指定锁,分别获得锁之后,执行synchronized方法体的内容。
package com.cn.test;
public class MultiThread {
private int num = 0;
public synchronized void printNum(String tag) throws InterruptedException{
if(tag.equals("a")){
num=100;
System.out.println("tag a. set num over");
Thread.sleep(1000);
}else{
num=200;
System.out.println("tag b. set num over");
}
System.out.println("tag "+tag+",num="+ num);
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
final MultiThread m1 =new MultiThread();
final MultiThread m2 =new MultiThread();
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
m1.printNum("a");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
m2.printNum("b");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}
打印结果:
tag a. set num over
tag b. set num over
tag b,num=200
tag a,num=100
一个对象有一把锁 当前m1 m2两个对象 m1执行时 获取的m1对象的锁 而m2 执行时获取的 是m2的锁 没有任何冲突不会有任何同步的效果;如果想同步的话 在方法上加static ,静态的方法上加上synchronized,获得锁就是类级别上的锁,所以会同步。
package com.cn.test;
public class MultiThread {
private static int num = 0;
public static synchronized void printNum(String tag) throws InterruptedException{
if(tag.equals("a")){
num=100;
System.out.println("tag a. set num over");
Thread.sleep(1000);
}else{
num=200;
System.out.println("tag b. set num over");
}
System.out.println("tag "+tag+",num="+ num);
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
final MultiThread m1 =new MultiThread();
final MultiThread m2 =new MultiThread();
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
m1.printNum("a");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
m2.printNum("b");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}
输出结果:
tag a. set num over
tag a,num=100
tag b. set num over
tag b,num=200
示例总结:
关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁,所以示例代码肿那个多线程先执行synchronized关键字的方法,那个线程就持有该方法所属对象的锁(Lock),两个对象,线程获得的就是两个不同的锁,他们互不影响
有一种情况则是相同的锁,即在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁。
3.对象锁的同步与异步
同步:synchronized 同步的概念就是共享,我们要牢牢记住共享这两个字,如果不是共享的资源,就没有必要进行同步。
异步:asynchronized 异步的概念就是独立,相互之间不受到任何制约。
同步的目的就是为了线程安全,对于 线程安全来说,需要满足两个特性:
原子性(同步)
可见性
package com.cn.test;
public class MyObject {
public synchronized void method1() throws InterruptedException{
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
}
/** synchronized **/
public void method2(){
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args){
final MyObject mo = new MyObject();
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
mo.method1();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
mo.method2();
}
});
t1.start();
t2.start();
}
}
输出结果:
Thread-0
Thread-1
并行执行 四秒后 结束
4.脏读:
ppackage com.cn.test;
public class DirtyRead {
private String usename="zs";
private String age="27";
public synchronized void setValue(String usename,String age) throws InterruptedException{
this.usename = usename;
Thread.sleep(2000);
this.age = age;
System.out.println("setValue usetname:"+usename+" age:"+age);
}
public void getValue(){
System.out.println("getValue usetname:"+this.usename+" age:"+this.age);
}
public static void main(String[] args) throws InterruptedException{
final DirtyRead dr = new DirtyRead();
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
try {
dr.setValue("lm", "28");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t1.start();
Thread.sleep(1000);
dr.getValue();
}
}
输出效果:
getValue usetname:lm age:27
setValue usetname:lm age:28
如果
public void synchronized getValue()
则输出:
setValue usetname:lm age:28
getValue usetname:lm age:28
5.synchronized 锁重入:
关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到了一个对象的锁后,再次请求此对象时是可以再次得到该对象的锁。
public class SyncDubbo1 {
public synchronized void method1(){
System.out.println("method1..");
method2();
}
public synchronized void method2(){
System.out.println("method2..");
method3();
}
public synchronized void method3(){
System.out.println("method3..");
}
public static void main(String[] args) {
final SyncDubbo1 sd = new SyncDubbo1();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
sd.method1();
}
});
t1.start();
}
}
输出结果:
method1..
method2..
method3..
public class SyncDubbo2 {
static class Main {
public int i = 10;
public synchronized void operationSup(){
try {
i--;
System.out.println("Main print i = " + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Sub extends Main {
public synchronized void operationSub(){
try {
while(i > 0) {
i--;
System.out.println("Sub print i = " + i);
Thread.sleep(100);
this.operationSup();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Sub sub = new Sub();
sub.operationSub();
}
});
t1.start();
}
}
输出结果:
Sub print i = 9
Main print i = 8
Sub print i = 7
Main print i = 6
Sub print i = 5
Main print i = 4
Sub print i = 3
Main print i = 2
Sub print i = 1
Main print i = 0
6.同一对象属性的修改不会影响锁的情况
public class ModifyLock {
private String name ;
private int age ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public synchronized void changeAttributte(String name, int age) {
try {
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 开始");
this.setName(name);
this.setAge(age);
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 修改对象内容为: "
+ this.getName() + ", " + this.getAge());
Thread.sleep(2000);
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
final ModifyLock modifyLock = new ModifyLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
modifyLock.changeAttributte("张三", 20);
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
modifyLock.changeAttributte("李四", 21);
}
},"t2");
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
当前线程 : t1 开始
当前线程 : t1 修改对象内容为: 张三, 20
当前线程 : t1 结束
当前线程 : t2 开始
当前线程 : t2 修改对象内容为: 李四, 21
当前线程 : t2 结束