参考:
同步的方式
1.使用synchronized关键字。
使用synchronized关键字修饰的方法会同步执行,必须要等上一个synchronized执行完才会继续执行,
如果在执行过程中线程阻塞,他就会一直保持等待的状态,在这里不特别推荐使用这种方式,
如果你的需求是必须保证数据同步的情况下且保证不会出现其他情况使用户无法完成操作的情况下可以使用时,可以使用。
这个关键字一般用于单例模式保证线程安全时使用。
无需手动释放或关闭,当操作完成后自动释放引用
2.使用lock这个锁的对象。
创建对象后使用lock.lock()方法进行加锁,
注意:这个lock必须要在finally代码块中进行unlock()的操作。
如果不进行手动释放这锁会一直存在引用,会造成很多意想不到的问题。比如可能频繁GC,严重就会ANR。
注意:关于Lock对象和synchronized关键字的选择:
a.最好两个都不用,使用一种java.util.concurrent包提供的机制,能够帮助用户处理所有与锁相关的代码。
b.如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码
c.如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁
多线程不安全示例:
public class TestActivity extends AppCompatActivity {
private static final String TAG = TestActivity.class.getSimpleName();
private int a = 0;
private void writeLog() {
for (int i = 0; i < 2; i++) {
try {
a++;
Log.e(TAG, i + " ++++++++============" +
Thread.currentThread().getName() +
" write 开始:" + a);
Thread.sleep(new Random().nextInt(1000));
a--;
Log.e(TAG, i + " ++++++++============" +
Thread.currentThread().getName() +
" write 结束:" + a);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void readLog() {
for (int i = 0; i < 2; i++) {
try {
Log.e(TAG, i + " --------============" +
Thread.currentThread().getName() +
" read 开始:" + a);
Thread.sleep(new Random().nextInt(1000));
Log.e(TAG, i + " --------============" +
Thread.currentThread().getName() +
" read 结束:" + a);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class WriteRunnable implements Runnable {
@Override
public void run() {
writeLog();
}
}
class ReadRunnable implements Runnable {
@Override
public void run() {
readLog();
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WriteRunnable writeRunnable = new WriteRunnable();
ReadRunnable readRunnable = new ReadRunnable();
for (int i = 0; i < 2; i++) {
new Thread(writeRunnable).start();
new Thread(readRunnable).start();
}
}
//不安全:
//0 ++++++++============Thread-6 write 开始:1
//0 --------============Thread-7 read 开始:1
//0 ++++++++============Thread-8 write 开始:2
//0 --------============Thread-9 read 开始:2
//0 ++++++++============Thread-8 write 结束:1
//1 ++++++++============Thread-8 write 开始:2
//1 ++++++++============Thread-8 write 结束:1
//0 --------============Thread-7 read 结束:1
//1 --------============Thread-7 read 开始:1
//0 --------============Thread-9 read 结束:1
//1 --------============Thread-9 read 开始:1
//0 ++++++++============Thread-6 write 结束:0
//1 ++++++++============Thread-6 write 开始:1
//1 --------============Thread-7 read 结束:1
//1 ++++++++============Thread-6 write 结束:0
//1 --------============Thread-9 read 结束:0
}
在write时,a++,之后a-- ,不应该出现值为2的现象,也不应该出现write还没结束,就开始read
synchronized 与 线程安全
public class TestActivity extends AppCompatActivity {
private static final String TAG = TestActivity.class.getSimpleName();
private int a = 0;
//synchronized这个关键字可以直接加到方法上也可使用synchronized代码块
//这里为方法上
private synchronized void writeLog() {
for (int i = 0; i < 2; i++) {
try {
a++;
Log.e(TAG, i + " ++++++++============" +
Thread.currentThread().getName() +
" write 开始:" + a);
Thread.sleep(new Random().nextInt(1000));
a--;
Log.e(TAG, i + " ++++++++============" +
Thread.currentThread().getName() +
" write 结束:" + a);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void readLog() {
//synchronized这个关键字可以直接加到方法上也可使用synchronized代码块
//这里为代码块
synchronized (this) {
for (int i = 0; i < 2; i++) {
try {
Log.e(TAG, i + " --------============" +
Thread.currentThread().getName() +
" read 开始:" + a);
Thread.sleep(new Random().nextInt(1000));
Log.e(TAG, i + " --------============" +
Thread.currentThread().getName() +
" read 结束:" + a);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class WriteRunnable implements Runnable {
@Override
public void run() {
writeLog();
}
}
class ReadRunnable implements Runnable {
@Override
public void run() {
readLog();
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WriteRunnable writeRunnable = new WriteRunnable();
ReadRunnable readRunnable = new ReadRunnable();
for (int i = 0; i < 2; i++) {
new Thread(writeRunnable).start();
new Thread(readRunnable).start();
}
}
//线程安全
//0 ++++++++============Thread-6 write 开始:1
//0 ++++++++============Thread-6 write 结束:0
//1 ++++++++============Thread-6 write 开始:1
//1 ++++++++============Thread-6 write 结束:0
//0 --------============Thread-7 read 开始:0
//0 --------============Thread-7 read 结束:0
//1 --------============Thread-7 read 开始:0
//1 --------============Thread-7 read 结束:0
//0 ++++++++============Thread-8 write 开始:1
//0 ++++++++============Thread-8 write 结束:0
//1 ++++++++============Thread-8 write 开始:1
//1 ++++++++============Thread-8 write 结束:0
//0 --------============Thread-9 read 开始:0
//0 --------============Thread-9 read 结束:0
//1 --------============Thread-9 read 开始:0
//1 --------============Thread-9 read 结束:0
}
ReentrantLock 与 线程安全 : 重入锁同步
在 JavaSE5.0中 新增了一个 java.util.concurrent 包来支持同步。
ReentrantLock类是可重入、互斥、实现了Lock接口的锁,
它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
ReenreantLock类的常用方法有:
ReentrantLock() : 创建一个ReentrantLock实例
lock() : 获得锁
unlock() : 释放锁
示例:
public class TestActivity extends AppCompatActivity {
private static final String TAG = TestActivity.class.getSimpleName();
private int a = 0;
private Lock lock = new ReentrantLock();
private void writeLog() {
for (int i = 0; i < 2; i++) {
try {
lock.lock(); //加锁
a++;
Log.e(TAG, i + " ++++++++============" +
Thread.currentThread().getName() +
" write 开始:" + a);
Thread.sleep(new Random().nextInt(1000));
a--;
Log.e(TAG, i + " ++++++++============" +
Thread.currentThread().getName() +
" write 结束:" + a);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); //释放锁
}
}
}
private void readLog() {
for (int i = 0; i < 2; i++) {
try {
lock.lock(); //加锁
Log.e(TAG, i + " --------============" +
Thread.currentThread().getName() +
" read 开始:" + a);
Thread.sleep(new Random().nextInt(1000));
Log.e(TAG, i + " --------============" +
Thread.currentThread().getName() +
" read 结束:" + a);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); //释放锁
}
}
}
class WriteRunnable implements Runnable {
@Override
public void run() {
writeLog();
}
}
class ReadRunnable implements Runnable {
@Override
public void run() {
readLog();
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WriteRunnable writeRunnable = new WriteRunnable();
ReadRunnable readRunnable = new ReadRunnable();
for (int i = 0; i < 2; i++) {
new Thread(writeRunnable).start();
new Thread(readRunnable).start();
}
}
//线程安全
//0 ++++++++============Thread-6 write 开始:1
//0 ++++++++============Thread-6 write 结束:0
//1 ++++++++============Thread-6 write 开始:1
//1 ++++++++============Thread-6 write 结束:0
//0 --------============Thread-7 read 开始:0
//0 --------============Thread-7 read 结束:0
//1 --------============Thread-7 read 开始:0
//1 --------============Thread-7 read 结束:0
//0 ++++++++============Thread-8 write 开始:1
//0 ++++++++============Thread-8 write 结束:0
//1 ++++++++============Thread-8 write 开始:1
//1 ++++++++============Thread-8 write 结束:0
//0 --------============Thread-9 read 开始:0
//0 --------============Thread-9 read 结束:0
//1 --------============Thread-9 read 开始:0
//1 --------============Thread-9 read 结束:0
}