线程安全

42 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

线程安全

线程漏洞最典型的例子就是网上售票。

new Thread(saleThread,"线程一");
new Thread(saleThread,"线程二");
new Thread(saleThread,"线程三");
new Thread(saleThread,"线程四");

上述会发生一张票被多次售出的情况。 归纳 当多线程共享一个共同资源时,会出现如上问题。 原因 线程随机性原理,即线程会被cpu随机切换。 解决方法

  1. 设置变量 if(bool) 可访问 if(!bool)不可访问

  2. synchronized 同步代码块

synchronized(lock){
  操作共享资源代码块
  }

同步方法

synchronized 返回值类型 方法名([参数1,...]){
  //balalala
}
public synchronized void set(String name) {

		if (isConsume) {
			count++;
			this.name = name + count;
			System.out.println(Thread.currentThread().getName() + "生产了"+ this.name);
			isConsume = false;
		}
		//
		notify();
		try {
			wait();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public synchronized void get() {
		if (!isConsume) {System.out.println(Thread.currentThread().getName() + "消费了" + name);
			isConsume = true;
		}
		notify();
		try {
			wait();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

}

3.lock替换synchronized java.util.concurrent.locks.Lock

    lock = new ReentrantLock();
    condition_producer = lock.newCondition();
    condition_consumer = lock.newCondition();

synchronized -> lock.lock();

public void set(String name) {
    lock.lock();
    try {
        //生产了
        condition_consumer.signal();
        // 消费了才出来生产
        condition_producer.await();        
    } finally {
        lock.unlock();// 必须执行!!!!!防止死锁!!
    }
}

public void get() {
    lock.lock();
    try {
         "消费了"
        condition_producer.notify();
        condition_consumer.wait();
    } finally {
        lock.unlock();
    }
}

Lock

  • void lock()

获取锁。

  • void lockInterruptibly()

如果当前线程未被中断,则获取锁。

  • Condition newCondition()

返回绑定到此 Lock 实例的新 Condition 实例。

  • boolean tryLock()

仅在调用时锁为空闲状态才获取该锁。

  • boolean tryLock(long time, TimeUnit unit)

如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。

  • void unlock()

释放锁。

wait(), notify(), notify All()

  • wait() 是当前cpu放弃同步锁并进入等待(释放cpu,释放锁),直到其他线程进入同步锁,并调用notify()或notify All()唤醒该线程为止
  • notify() 唤醒同步锁上等待的第一个调用wait()的线程
  • notify All() 唤醒同步锁上调用wait()的所有线程 注意: 上述三种方法必须在同步代码块或同步方法里 必须由锁对象调用 IllegalMonitorStateException 非法的监控异常

sleep()和wait()的区别

描述sleepwait
属于哪个类ThreadObject
是否让出cpu
是否释放锁
时间可以可以
使用要求必须在同步里面,锁对象调用
中断InterruptedException线程终止线程终止
#线程状态
  • BLOCKED

受阻塞并且正在等待监视器锁的某一线程的线程状态。

	public void run() {

		synchronized (this) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}
	}

    public static void main(String[] args) {
		ThreadBlocked ttw = new ThreadBlocked();
		Thread thread1 = new Thread(ttw);
		Thread thread2 = new Thread(ttw);
		thread1.start();
		thread2.start();
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(thread2.getState());
	}
  • NEW

至今尚未启动的线程的状态。

	public void run() {}

	public static void main(String[] args) {
		Thread thread = new Thread();
		/**休眠一下 给时间切换到线程thread 否则输出主线程main的状态**/
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(thread.getState());
	}
  • RUNNABLE

可运行线程的线程状态。

	public void run() {}

	public static void main(String[] args) {
		Thread thread = new Thread();
		thread.start();
		System.out.println(thread.getState());
	}

  • TERMINATED

已终止线程的线程状态。

	public void run() {}

	public static void main(String[] args) {
		ThreadTerminated ttw = new ThreadTerminated();
		Thread thread = new Thread(ttw);
		thread.start();
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(thread.getState());
	}
  • TIMED_WAITING

具有指定等待时间的某一等待线程的线程状态。

public void run() {
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		ThreadTimeWaiting ttw = new ThreadTimeWaiting();
		Thread thread = new Thread(ttw);
		thread.start();
		/**
		 * 休眠一下 切换到线程thread 否则输出主线程main的状态
		 */
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(thread.getState());
	}
  • WAITING

某一等待线程的线程状态。

public void run() {
		synchronized (this) {
			try {
				wait();
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}

		}
	}

	public static void main(String[] args) {
		ThreadWaiting ttw = new ThreadWaiting();
		Thread thread = new Thread(ttw);
		thread.start();
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(thread.getState());
	}

线程池

管理线程,存放等待线程 Thread创建的线程不在线程池里面。 通过线程池创建的线程默认为后台线程,优先级默认为Normal. 执行方法execute,结束方法shutdown


优点:线程的创建与销毁都要耗费大量的时间,创建多线程也会占据大量的空间。线程池的出现不仅利于管理,还解决了上述问题。