回顾
1、线程与进程
进程:正在运行的程序,进程包含至少一个或多个线程
2、创建线程的方式
- 实现Runable接口
- 继承Thread类(不建议使用,java是单继承,可扩展性差),用start方法通知cpu创建一个线程
- 但在公司中一般都是用Callable接口,Runable接口的效率比Callable的相对较低
- 使用线程池ThreadPoolExecutor
3、java真的可以开启线程吗
实际上我们调用的start()方法本质上是调用了系统的C++程序,这个程序才是真正操作计算机硬件的,而我们的java程序不是直接运行在操作系统上而是运行在JVM上,所以java程序无法直接操作硬件。
4、并发(队列+锁)与并行
并发:多个线程操作同一资源,单核,模拟出多条线程,天下武功,唯快不破,快速交替
并行(一起行走):多个cup,多个线程同时进行,使用线程池
并发编程的本质:充分利用cpu的资源/时间
5、synchronized与lock锁
- synchronized 是java内置关键字,lock是一个java类。
- synchronized 会自动释放锁,lock需要手动加锁,会死锁。
- synchronized (线程1(获得锁,阻塞),线程2(傻傻的等待)),lock会尝试获取锁
- synchronized 适合锁少量代码,lock适合锁大量代码
- synchronized 不会判断锁定状态,lock会判断是否有锁
- synchronized 可重入锁,非公平,lock ,可重入锁,自己设置非公平或公平
6、wait()与sleep()
- wait()--->来自object类,sleep()---->来自Thread类
- wait()---->人醒着,在等待 ,会释放锁 ; sleep()---->人在睡觉,不会释放锁
预科
1、获取cpu核数
public class saleTicket {
public static void main(String[] args) {
//开启多个线程去买票
Ticket ticket=new Ticket();
//使用lambda表达式,简洁代码
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sale();
}
}).start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sale();
}
}).start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sale();
}
}).start();
}
}
//实际编程,高内聚,低耦合
//oop编程,代码干净,简洁
class Ticket{
private int num=20;
//卖票方法
public synchronized void sale(){
if(num>0) {
System.out.println(Thread.currentThread().getName() + "买了第" + (num--) + "票===" + "剩余" + num);
}
}
}
3、lock锁:与synchronized实现同样的效果
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class saleTicket2 {
public static void main(String[] args) {
Ticket2 ticket=new Ticket2();
//使用lambda表达式,简洁代码
new Thread(()->{ for (int i = 0; i < 30; i++) ticket.sale();},"A").start();
new Thread(()->{ for (int i = 0; i < 30; i++) ticket.sale();},"B").start();
new Thread(()->{ for (int i = 0; i < 30; i++) ticket.sale();},"C").start();
}
}
//使用lock锁
/*1、new ReentrantLock()一把锁
* 2、加锁 lock()
* 3、释放锁 unlock()
* */
class Ticket2{
private int num=20;
//卖票方法
public synchronized void sale(){
Lock lock=new ReentrantLock();
lock.lock();
try {//业务
if(num>0) {
System.out.println(Thread.currentThread().getName() + "买了第" + (num--) + "票===" + "剩余" + num);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
6、生产者消费者问题之lock的精准通知
新技术的出现不仅仅为了覆盖传统技术,还有对技术的补充和升级
lock锁与synchronized都能实现同样的效果,但是如何做到有序的使用资源即精准的通知,如:A线程昨晚去通知B线程,B->C->D,这样ABCD轮流,只有lock锁能实现
- 传统的synchronized解决
能够解决资源抢夺问题,但不能保证线程顺序
//使用传统的synchronized方法时
//超过两个线程对资源进行操作时,synchronized无法保证线程的安全了
//由此引发一个问题,”虚假唤醒“
/*虚假唤醒的问题在于,只进行了一次判断,但是虚假唤醒总是有可能发生,所以建议使用循环
if(number!=0){//等待
this.wait();
}
*
* */
public class oldPC {
public static void main(String[] args) {
Data data=new Data();
new Thread(()->{ for (int i = 0; i <20 ; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{ for (int i = 0; i <20 ; i++) {
try {
data.decrese();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{ for (int i = 0; i <20 ; i++) {
try {
data.decrese();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{ for (int i = 0; i <20 ; i++) {
try {
data.decrese();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//oop编程
class Data{
private int number=0;
//+1操作
public synchronized void increment() throws InterruptedException {
while(number!=0){//等待
this.wait();
}
//执行+1后唤醒其他线程
number++;
System.out.println(Thread.currentThread().getName()+"执行了==>"+number);
this.notifyAll();
}
//-1操作
public synchronized void decrese() throws InterruptedException {
while(number==0){//等待
this.wait();
}
//执行-1后唤醒其他线程
number--;
System.out.println(Thread.currentThread().getName()+"执行了==>"+number);
this.notifyAll();
}
}
-使用lock方式:
lock去newCondition,使用方法await(),signal()
public class NewPC {
public static void main(String[] args) {
Data2 data2=new Data2();
new Thread(()->{for (int i = 0; i < 20; i++) data2.increse();},"A").start();
new Thread(()->{for (int i = 0; i < 20; i++) data2.decrese();},"B").start();
new Thread(()->{for (int i = 0; i < 20; i++) data2.increse();},"C").start();
// new Thread(()->{for (int i = 0; i < 20; i++) data2.decrese();},"D").start();
}
}
/*使用lock方式
* 通过lock去newCondition
* 使用await(),signal()
* */
class Data2{
private int number=0;
Lock lock=new ReentrantLock();
Condition condition1=lock.newCondition();
Condition condition2=lock.newCondition();
//+1操作
public void increse(){
lock.lock();
try {
//判断是否等待
while (number!=0){
condition1.await();//等待
}
number++;
System.out.println(Thread.currentThread().getName()+"执行了加===>
标签:java,synchronized,Thread,lock,void,编程,并发,new,public
From: https://www.cnblogs.com/littleworld/p/17146229.html