死锁
当两个线程的内部是 嵌套 锁定 执行两个相同对象,比如线程一里面先枷锁执行a对象,再在操作a对象的代码块里面加锁执行b对象,而线程二里面先加锁执行b对象,再在操作b对象的代码块中执行a对象,然后互相等待对方执行完成,以至于发生死锁,可看下图辅助理解
public class DeadLock {
public static void main(String[] args) {
Object o1=new Object();
Object o2=new Object();
Thread t1=new Thread(new A(o1,o2));
Thread t2=new Thread(new B(o1,o2));
t1.setName("俺是A");
t2.setName("俺是B");
t1.start();
t2.start();
}
}
class A implements Runnable{
Object o1;
Object o2;
public A(Object o1,Object o2) {
this.o1=o1;
this.o2=o2;
}
@Override
public void run() {
synchronized(o2) {
//加入睡眠是为了确定死锁一定会发生
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"锁住o2了");
synchronized(o1) {
System.out.println(Thread.currentThread().getName()+"锁住o1了");
}
}
}
}
class B implements Runnable{
Object o1;
Object o2;
public B(Object o1,Object o2) {
this.o1=o1;
this.o2=o2;
}
@Override
public void run() {
synchronized(o1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"锁住o1了");
synchronized(o2) {
System.out.println(Thread.currentThread().getName()+"锁住o2了");
}
}
}
}
Object中的方法
wait(),将当前操作对象的线程挂起,会释放锁,让其他方法进行访问,
无参时或者参数为0时,表示不会自动唤醒,需要用notify方法进行唤醒;如果有一个long类型的参数,则表示到了指定时间后自动唤醒。
notify(),唤醒正在等待操作当前对象的其他某一线程
notifyAll(),唤醒正在等着操作对象的其他所有线程
守护线程
每个程序运行时,都会由一个守护线程进行监听程序是否正常运行
public class DaemonThread {
public static void main(String[] args) {
Thread thr = new Thread(new DaemonT());
//设置thr对象为守护线程,且设置守护线程要在start()方法之间设置
thr.setDaemon(true);
thr.start();
// 当主线程执行完毕,jvm关机,守护线程终止
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
}
}
class DaemonT implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("sss");
}
}
}
生产者与消费者
生产者与消费者模式是,有一个中间容器,当生产者生产完产品之后,会将产品放到这个中间容器也叫缓冲区,而消费者则直接从缓冲区拿产品,降低了生产者与消费者之间的强耦合,所以此模式是为了降低耦合度
public class ProducerCustomer {
public static void main(String[] args) {
ProdCus pc = new ProdCus();
Thread pro = new Thread(new Producer(pc));
Thread cus = new Thread(new Customer(pc));
pro.setName("生产者");
cus.setName("消费者");
pro.start();
cus.start();
}
}
class Producer implements Runnable {
private ProdCus pc;
public Producer(ProdCus pc) {
this.pc = pc;
}
@Override
public void run() {
for (int i = 0; i < 15; i++) {
pc.pro((char) ('a' + i));
}
}
}
class Customer implements Runnable {
private ProdCus pc;
public Customer(ProdCus pc) {
this.pc = pc;
}
@Override
public void run() {
for (int i = 0; i < 15; i++) {
pc.cus();
}
}
}
//业务类
class ProdCus {
// 缓冲区
char[] chars = new char[8];
// 保存的个数,数量-1为数组下标
int count = 0;
// 放产品
public synchronized void pro(char product) {
// 当产品满了则等待消费者拿商品
if (count == chars.length) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count == 0)
this.notifyAll();
// 放产品
chars[count++] = product;
System.out.println("生产了" + chars[count- 1] + "共有" + count + "件产品");
}
// 拿产品
public synchronized void cus() {
// 当产品没了,就需要等待生产者生产商品
if (count == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count ==chars.length)
this.notifyAll();
// 拿走一个产品
System.out.println("消费了" + chars[--count] + "还剩" + count + "件产品");
}
}
单例模式
懒汉模式与饿汉模式在多线程模式下,只有懒汉模式会发生错误,因为饿汉模式在类加载时就创建了对象,多线程调用时就一直是这个对象;而懒汉模式则会在判断静态类类型的类变量是否为null时,进去多个线程,然后导致创建了多了对象,并进行赋值,以至于错误。
所以需要对创建并赋值对象的这段代码加锁,而给这块代码加锁后,在一个线程进去,其他线程就需要排队等待这个线程执行完毕,这样可能会效率较低,所以当对象创建并赋值时,应该让其他线程知道并不用等待,直接结束。
所以要用到双验证加锁机制进行设计
public class Singleton {
public static void main(String[] args) {
new Thread(new A1()).start();
new Thread(new A1()).start();
new Thread(new A1()).start();
new Thread(new A1()).start();
new Thread(new A1()).start();
new Thread(new A1()).start();
}
private static Singleton obj;
private Singleton() {
}
// public static Singleton getInstance() {
// if (obj == null)// 另一个线程判断为null,也进来了
// obj = new Singleton();// 多线程时,一个线程进行到这里还未赋值
// return obj;
// }
public static Singleton getInstance() {
if (obj == null) {
synchronized (Singleton.class) {
if (obj == null)
obj = new Singleton();//当他进行赋值时,其他线程不用排队,直接返回结果
}
}
return obj;
}
}
class A1 implements Runnable {
@Override
public void run() {
System.out.println(Singleton.getInstance());
}
}