1、使用synchronized包裹代码块或者修饰方法
java的每个对象都有一个内置锁,要执行synchronized代码块必须获得内置锁。
2、使用wait/notify等待唤醒
3、使用特殊域变量volatile关键字修饰变量
4、使用重入锁ReentrantLock
ReenTrantLock lock = new ReenTrantLock();
lock.lock();
lock.unlock();
5、使用ThreadLocal局部变量
如果使用ThreadLocal管理变量,每个线程访问该变量都会获得该变量的副本,副本与副本之间相互独立,这样线程与线程之间就互不影响,解决多线程访问变量冲突的问题,这是以空间换时间
6、使用阻塞式队列实现同步
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
queue.put(x) -->向队尾添加元素,当队列满时阻塞
queue.take() -->移除并返回队头元素,当队列为空时阻塞
实例一:
用两个线程一个对变量执行加一一个对变量执行减一操作,实现线程同步。
这里使用内部类和synthronized同步代码块和同步方法分别实现
package com.hy.springmvc.thread;
public class ThreadAddSub {
private int i = 0;
private synchronized void add() {
i++;
System.out.println(Thread.currentThread().getName() + "--add i=" +i);
}
private void add1() {
synchronized (this) {
i++;
System.out.println(Thread.currentThread().getName() + "--add i=" +i);
}
}
private synchronized void sub() {
i--;
System.out.println(Thread.currentThread().getName() + "--sub i=" +i);
}
private void sub1() {
synchronized (this) {
i--;
System.out.println(Thread.currentThread().getName() + "--sub i=" +i);
}
}
class ThreadAdd implements Runnable{
@Override
public void run() {
for (int i = 0; i < 21; i++) {
add1();
}
}
}
class ThreadSub implements Runnable {
@Override
public void run() {
for (int i = 0; i < 21; i++) {
sub1();
}
}
}
public static void main(String[] args) {
ThreadAddSub addSub = new ThreadAddSub();
ThreadAdd add = addSub.new ThreadAdd();
ThreadSub sub = addSub.new ThreadSub();
Thread t1 = new Thread(add);
t1.start();
Thread t2 = new Thread(sub);
t2.start();
}
}
执行结果分析:
当加和减的此时相等时,最终变量一定是0
注意:
内部类的使用方法:
静态内部类(使用static修饰的内部类):B b = A.new B();
非静态内部类:A a = new A(); B b = a.new B();