下一篇: 并发编程的基础
什么是线程安全

从图中可以看出线程安全只要包括变量在多个线程之间共享、生命周期内状态可以改变、最后结果和预期一致,就是线程安全的。
Synchronized的三种使用方式
1.普通同步方法(实例方法)锁是当前实例对象,进入同步代码前要获得当前实例的锁
2.静态同步方法,锁是当前类的class对象,进入同步代码前要获得当前类对象的锁
3.同步方法块,锁是括号里面的对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
作用在实例方法
- 多个线程访问同一个对象的同一个synchronized方法
public class SynchronizedTest implements Runnable{
static int i = 0;
/**
* 修饰实例方法
*/
public synchronized void increase(){
System.out.println("测试:"+Thread.currentThread().getName()+",i="+i++);
}
@Override
public void run() {
for(int j = 0;j < 10; j++){
increase();
}
}
public static void main(String[] args) throws InterruptedException {
SynchronizedTest synchronizedTest = new SynchronizedTest();
Thread t1 = new Thread(synchronizedTest);
Thread t2 = new Thread(synchronizedTest);
t1.setName("线程1");
t1.start();
t1.join();
t2.setName("线程2");
t2.start();
t2.join();
System.out.println(i);
}
}
执行结果:
测试:线程1,i=0
测试:线程1,i=1
测试:线程1,i=2
测试:线程1,i=3
测试:线程1,i=4
测试:线程1,i=5
测试:线程1,i=6
测试:线程1,i=7
测试:线程1,i=8
测试:线程1,i=9
测试:线程2,i=10
测试:线程2,i=11
测试:线程2,i=12
测试:线程2,i=13
测试:线程2,i=14
测试:线程2,i=15
测试:线程2,i=16
测试:线程2,i=17
测试:线程2,i=18
测试:线程2,i=19
20
从结果看线程1和线程2顺序执行,因为一个对象只有一把锁,当一个线程获取了该对象的锁之后,其它线程无法获得该对象的锁,只有锁释放以后才可以获得,所以保证了正确的执行结果。
多个线程访问同一个对象的不同的synchronized方法
public class SynchronizedTest{
public synchronized void testMethod1(){
System.out.println("testMethod1 start:"+Thread.currentThread().getName());
try {
System.out.println("testMethod1:"+Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("testMethod1 end:"+Thread.currentThread().getName());
}
public synchronized void testMethod2(){
System.out.println("testMethod2 start:"+Thread.currentThread().getName());
try {
System.out.println("testMethod2:"+Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("testMethod2 end:"+Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
SynchronizedTest synchronizedTest = new SynchronizedTest();
new Thread(new Runnable() {
@Override
public void run() {
synchronizedTest.testMethod1();
}
},"线程1").start();
new Thread(new Runnable() {
@Override
public void run() {
synchronizedTest.testMethod2();
}
},"线程2").start();
}
}
**执行结果:**
```html
testMethod1 start:线程1
testMethod1:线程1
testMethod1 end:线程1
testMethod2 start:线程2
testMethod2:线程2
testMethod2 end:线程2
Process finished with exit code 0
从程序执行结果可以看出来,线程1和线程2是顺序执行,也就是说当多个线程访问同一个对象的不同的synchronized方法时,其实获取的是同一把锁,必须等待当前锁的释放。
- 多个线程访问同一个对象的synchronized方法和非synchronized方法
public class SynchronizedTest{
public synchronized void testMethod1(){
System.out.println("testMethod1 start:"+Thread.currentThread().getName());
try {
System.out.println("testMethod1:"+Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("testMethod1 end:"+Thread.currentThread().getName());
}
public void testMethod2(){
System.out.println("testMethod2 start:"+Thread.currentThread().getName());
try {
System.out.println("testMethod2:"+Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("testMethod2 end:"+Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
SynchronizedTest synchronizedTest = new SynchronizedTest();
new Thread(new Runnable() {
@Override
public void run() {
synchronizedTest.testMethod1();
}
},"线程1").start();
new Thread(new Runnable() {
@Override
public void run() {
synchronizedTest.testMethod2();
}
},"线程2").start();
}
}
执行结果:
testMethod1 start:线程1
testMethod2 start:线程2
testMethod2:线程2
testMethod1:线程1
testMethod1 end:线程1
testMethod2 end:线程2
Process finished with exit code 0
从结果可以看出线程1和线程2交叉执行,说明了访问synchronized方法得时候可以访问非synchronized方法。
- 多个线程作用在不同对象上
public class SynchronizedTest{
public void testMethod1(){
System.out.println("testMethod1 start:"+Thread.currentThread().getName());
try {
System.out.println("testMethod1:"+Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("testMethod1 end:"+Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
new SynchronizedTest().testMethod1();
}
},"线程1").start();
new Thread(new Runnable() {
@Override
public void run() {
new SynchronizedTest().testMethod1();
}
},"线程2").start();
}
}
执行结果:
testMethod1 start:线程1
testMethod1:线程1
testMethod1 start:线程2
testMethod1:线程2
testMethod1 end:线程1
testMethod1 end:线程2
Process finished with exit code 0
上面是两个线程操作了2个对象是不同的锁,执行结果也可以看出线程1和线程2是交叉执行,所以线程之间各不影响。
作用在静态方法
public class SynchronizedTest implements Runnable{
static int i = 0;
/**
* 修饰实例方法
*/
public static synchronized void increase(){
System.out.println("测试:"+Thread.currentThread().getName()+",i="+i++);
}
@Override
public void run() {
for(int j = 0;j < 5; j++){
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new SynchronizedTest());
Thread t2 = new Thread(new SynchronizedTest());
t1.setName("线程1");
t1.start();
t1.join();
t2.setName("线程2");
t2.start();
t2.join();
System.out.println(i);
}
}
执行结果:
测试:线程1,i=0
测试:线程1,i=1
测试:线程1,i=2
测试:线程1,i=3
测试:线程1,i=4
测试:线程2,i=5
测试:线程2,i=6
测试:线程2,i=7
测试:线程2,i=8
测试:线程2,i=9
10
Process finished with exit code 0
线程1和线程2实例化两个不同的对象,但是访问的是静态方法,但两个线程发生了互斥,因为静态方法是依附于类而不是对象的,当synchronized修饰静态方法时,锁是class对象。
作用在代码块
public class SynchronizedTest implements Runnable{
private static SynchronizedTest synchronizedTest = new SynchronizedTest();
static int i = 0;
/**
* 修饰实例方法
*/
public void increase(){
synchronized (this) {
System.out.println("测试:" + Thread.currentThread().getName() + ",i=" + i++);
}
}
@Override
public void run() {
for(int j = 0;j < 5; j++){
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(synchronizedTest);
Thread t2 = new Thread(synchronizedTest);
t1.setName("线程1");
t1.start();
t1.join();
t2.setName("线程2");
t2.start();
t2.join();
System.out.println(i);
}
}
执行结果:
测试:线程1,i=0
测试:线程1,i=1
测试:线程1,i=2
测试:线程1,i=3
测试:线程1,i=4
测试:线程2,i=5
测试:线程2,i=6
测试:线程2,i=7
测试:线程2,i=8
测试:线程2,i=9
10
Process finished with exit code 0
代码块的实现方式比方法级别的锁的粒度更小,有利于提高程序的性能。
总结

版权声明:本文为qq_16438883原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。