锁的种类
1.类锁
持有该类的字节码对象的锁
public static synchronized void xx(){}
public void xx(){
synchronized(xx.class){
}
}
2.对象锁
持有该类对象的锁,前两种持有的是XX.this,最后一种持有的是成员变量的锁
public synchronized void xx(){}
public void xx(){
synchronized(this){
}
}
Object obj=new Object();
public void xx(){
synchronized(obj){
}
}
3.显示锁
显示锁就是程序员在代码中可以控制加锁,释放锁的操作。类锁和对象锁都是使用synchronized关键字来加锁,他在native帮我们完成了加锁和释放锁的操作,因此synchronized也被称为内置锁。
ReentrantLock lock=new ReentrantLock();
public void xx(){
lock.lock();
xxxxxxxxx;
lock.unlock();
}
Synchronized和ReentrantLock
这两种锁都是重入锁,代表在递归方法中还可以继续获取锁,内部有一个计数器来计算我们获取同一个锁的次数
这两种锁都是非公平锁
new ReentrantLock(true);是公平锁
非公平锁效率比较高
public synchronized void xx(){
xxxxxxxxxx;
xx();
}
wait和notify
wait和notify都必须在synchronized中使用。因为notify和wait在进行操作时都必须获取当前锁,但是当执行完wait和notify之后会释放自己持有的锁。
public synchronized void xx(){
xxxxxxxxxxxx;
notify();
wait();
}
生产者和消费者
模拟生产和消费者去生产和消费面包
public class Test {
static class Container{
private int id;
private boolean flag;
public synchronized void out(){
if (flag) {
System.out.println("当前线程:" + Thread.currentThread().getName() + ",消费了" + this.id);
flag=false;
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void put(){
if (!flag) {
id += 1;
System.out.println("当前线程:" + Thread.currentThread().getName() + "------------------,生产了" + this.id);
flag=true;
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class ProduceThread implements Runnable{
private Container container;
public ProduceThread(Container container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
container.put();
}
}
}
static class ConsumerThread implements Runnable{
private Container container;
public ConsumerThread(Container container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
container.out();
}
}
}
public static void main(String[] args) {
Container container = new Container();
new Thread(new ProduceThread(container)).start();
new Thread(new ConsumerThread(container)).start();
}
}
之前面试遇到过相似的题目
有一个数组,{1,2,3,4,5,6...},使用两个线程,线程A打印奇数,线程B打印偶数
解决方案:
public class Demo {
static class Print{
private int i=0;
private int[] data;
private boolean flag;
public Print(int[] data) {
this.data = data;
}
public synchronized void printJ(){
if (!flag){
System.out.println(data[i]);
i++;
flag=true;
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void printO(){
if (flag){
System.out.println(data[i]);
i++;
flag=false;
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class A extends Thread{
private Print print;
public A(Print print) {
this.print = print;
}
@Override
public void run() {
super.run();
while (print.i<print.data.length){
print.printJ();
}
}
}
static class B extends Thread{
private Print print;
public B(Print print) {
this.print = print;
}
@Override
public void run() {
super.run();
while (print.i<print.data.length){
print.printO();
}
}
}
public static void main(String[] args) {
Print print = new Print(new int[]{1, 2, 3, 4, 5});
new A(print).start();
new B(print).start();
}
}
网友评论