进程和线程是什么
进程是操作系统分配资源的最小单元,而线程是cpu调度的最小单元。
java默认有几个线程
2个,main线程和GC线程(GC垃圾回收机制)
java可以开启线程么
不能
并发和并行
并发,多线程操作同一个资源,cpu单核,模拟多条线程,快速交替
并行,多人一起走,cpu多核,多个线程可以同时执行,线程池
package main;
public class Demo1 {
public static void main(String[] args) {
//获取cpu的核数
//cpu密集型,io密集型
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
示例:
线程有几个状态:
Thread.State
public enum State {
/**
* 新建状态
*/
NEW,
/**
* 运行状态
*/
RUNNABLE,
/**
* 堵塞状态
*/
BLOCKED,
/**
* 等待状态
*/
WAITING,
/**
* 超时等待
*/
TIMED_WAITING,
/**
* 终止状态
*/
TERMINATED;
}
1.来自不同类,wait->Object,sleep->Thread
2.锁的释放,wait->释放锁,sleep->不释放锁
3.使用范围,wait->同步代码块,sleep->任何地方
package main;
/*
* 真正的多线程开发,公司中的开发,降低耦合型
* 线程就是一个单独的资源类,没有任何附属的操作!
* 1. 属性 方法
* */
public class TicketSale {
public static void main(String[] args) {
//并发:多线程操作同一个资源类,把资源丢入线程
Ticket ticket = new Ticket();
//@FunctionalInterface 函数式接口,jkd1.8 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();
}
}
//资源类OOP
class Ticket{
//属性 方法
private int number = 30;
//卖票的方式
public synchronized void sale(){
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余"+number);
}
}
}
Class ReentrantLock 构造方法 | |
---|---|
public ReentrantLock() | 创建一个ReentrantLock的实例。 这相当于使用ReentrantLock(false) |
public ReentrantLock(boolean fair) | 根据给定的公平政策创建一个 ReentrantLock的实例. fair - true如果此锁应使用合理的订购策略 |
package main;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* 真正的多线程开发,公司中的开发,降低耦合型
* 线程就是一个单独的资源类,没有任何附属的操作!
* 1. 属性 方法
* */
public class TicketSale2 {
public static void main(String[] args) {
//并发:多线程操作同一个资源类,把资源丢入线程
Ticket2 ticket = new Ticket2();
//@FunctionalInterface 函数式接口,jkd1.8 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.lock();//加锁
* 3.finally-> lock.unlock() //解锁
* */
class Ticket2{
//属性 方法
private int number = 30;
//卖票的方式
Lock lock = new ReentrantLock();
public void sale(){
lock.lock();//加锁
try {
//业务代码
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余"+number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();//解锁
}
}
}
/*
公平锁
线程1购买了第10张票
线程2购买了第9张票
线程3购买了第8张票
线程1购买了第7张票
线程2购买了第6张票
线程3购买了第5张票
线程1购买了第4张票
线程2购买了第3张票
线程3购买了第2张票
线程1购买了第1张票
非公平锁
线程1购买了第10张票
线程1购买了第9张票
线程1购买了第8张票
线程1购买了第7张票
线程1购买了第6张票
线程1购买了第5张票
线程1购买了第4张票
线程1购买了第3张票
线程1购买了第2张票
线程1购买了第1张票
*/
- lock是一个接口,而synchronized是java的一个关键字。
- synchronized在发生异常时会自动释放占有的锁,因此不会出现死锁;而lock发生异常时,不会主动释放占有的锁,必须手动来释放锁,可能引起死锁的发生。
- Synchronized 可重入锁,不可以中断的,非公平; Lock ,可重入锁,可以判断锁,非公平(可以自己设置);
- Synchronized适合锁少量的代码同步问题,Lock适合锁大量的同步代码!
- Synchronized 线程1(获得锁,阻塞)、绩程2(等待,傻傻的等) ; Lock锁就不一定会等待下去;
- Synchronized无法判断获取锁的状态,Lock 可以判断是否获取到了锁
Lock
package pc;
/*
* 线程之间的通信问题:生产者和消费者问题 等待唤醒 ,通知唤醒
* 线程交替执行 A B 操作同一个变量 num = 0;
* A num+1
* B num-1
* */
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
//等待 业务 通知
class Data{//数字 资源类
private int number = 0;
public synchronized void increment() throws InterruptedException {
if (number != 0) {
//等待
this.wait();
}
number++;
//通知其他线程,我+1完毕了
System.out.println(Thread.currentThread().getName()+"-->"+number);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
if (number == 0) {
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"-->"+number);
this.notifyAll();
}
}
四个线程时(两个生产者两个消费者)出现虚假唤醒问题,需要使用while来替换if来判断唤醒后是否可以继续执行
理解 : 拿两个加法线程A、B来说,比如A先执行,执行时调用了wait方法,那它会等待,此时会释放锁,那么线程B获得锁并且也会执行wait方法,两个加线程一起等待被唤醒。此时减线程中的某一个线程执行完毕并且唤醒了这俩加线程,那么这俩加线程不会一起执行,其中A获取了锁并且加1,执行完毕之后B再执行。如果是if的话,那么A修改完num后,B不会再去判断num的值,直接会给num+1。如果是while的话,A执行完之后,B还会去判断num的值,因此就不会执行
package pc;
/*
* 线程之间的通信问题:生产者和消费者问题 等待唤醒 ,通知唤醒
* 线程交替执行 A B 操作同一个变量 num = 0;
* A num+1
* B num-1
* */
public class A {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//等待 业务 通知
class Data{//数字 资源类
private int number = 0;
public synchronized void increment() throws InterruptedException {
while (number != 0) {
//等待
this.wait();
}
number++;
//通知其他线程,我+1完毕了
System.out.println(Thread.currentThread().getName()+"-->"+number);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while (number == 0) {
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"-->"+number);
this.notifyAll();
}
}
await:
signalAll:
package pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class B {
public static void main(String[] args) {
Data2 data = new Data2();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//等待 业务 通知
class Data2 {//数字 资源类
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// condition.await();//等待
// condition.signalAll();//唤醒全部
public void increment() throws InterruptedException {
lock.lock();
try {
//业务代码
while (number != 0) {
//等待
condition.await();
}
number++;
//通知其他线程,我+1完毕了
System.out.println(Thread.currentThread().getName() + "-->" + number);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() throws InterruptedException {
lock.lock();
try {
while (number == 0) {
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "-->" + number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
await:
signal:
package pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class C {
public static void main(String[] args) {
Data3 data = new Data3();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data.printA();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data.printB();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data.printC();
}
}, "C").start();
}
}
class Data3 {// 资源类 Lock
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int number = 1;
public void printA() {
lock.lock();
try {
//业务,判断->执行->通知
while (number != 1) {
//等待
condition1.await();
}
System.out.println(Thread.currentThread().getName() + "--->A");
//唤醒指定的人:B
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
//业务,判断->执行->通知
while (number != 2) {
//等待
condition2.await();
}
System.out.println(Thread.currentThread().getName() + "--->B");
//唤醒指定的人:C
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
//业务,判断->执行->通知
while (number!=3){
//等待
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"--->C");
number=1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
package lock;
import java.util.concurrent.TimeUnit;
/*
* 1.标准情况下,两个线程先打印发短信还是打电话?1.发短信﹑2.打电话
* 2.sendSms延迟4秒,两个线程先打印 发短信还是 打电话?1.发短信 2.打电话
* */
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
//锁的存在
new Thread(()->{
phone.sendSms();
},"A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
//synchronized 锁的对象是方法的调用者
//两个方法是同一个锁,谁先拿到谁先执行
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
结果:
package com.example.juc.test;
import java.util.concurrent.TimeUnit;
/*
* 3.增加了一个普通方法,先发短信还是Hello
* 4.两个对象,两个同步方法,先发短信还是先打电话
* */
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
//两个对象,两个调用者,两把锁!
Phone phone = new Phone();
Phone phone2 = new Phone();
//锁的存在
new Thread(()->{
System.out.println(Thread.currentThread().getName());
phone.hello();
phone.sendSms();
},"A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
System.out.println(Thread.currentThread().getName());
phone2.hello();
phone2.call();
},"B").start();
}
}
class Phone{
//synchronized 锁的对象是方法的调用者
//两个方法是同一个锁,谁先拿到谁先执行
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
//这里没有锁,不是同步方法,不受锁的影响
public void hello(){
System.out.println("hello");
}
}
结果:
package com.example.juc.test;
import java.util.concurrent.TimeUnit;
/*
* 5.增加两个静态的同步方法,只有一个对象,先打印 发短信还是打电话
* 6.两个对象!增加两个静态的同步方法, 先打印 发短信还是打电话
* */
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
//两个对象的Class类模板只有一个,static,锁的是Class
Phone phone = new Phone();
Phone phone2 = new Phone();
//锁的存在
new Thread(()->{
phone.sendSms();
},"A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
phone2.call();
},"B").start();
}
}
//Phone唯一的一个Class对象
class Phone{
//synchronized 锁的对象是方法的调用者
//static 静态方法
//类一加载就有了!锁的是Class
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
结果:
package com.example.juc.test;
import java.util.concurrent.TimeUnit;
/*
* 7.1个静态的同步方法,1个普通的同步方法,1个对象,先打印谁
* 8.1个静态的同步方法,1个普通的同步方法,2个对象,先打印谁
* */
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
//两个对象的Class类模板只有一个,static,锁的是Class
Phone phone = new Phone();
Phone phone2 = new Phone();
//锁的存在
new Thread(() -> {
phone.sendSms();
}, "A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
phone2.call();
}, "B").start();
}
}
//Phone唯一的一个Class对象
class Phone {
//静态的同步方法 锁的是Class类模板
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//普通的同步方法 锁的调用者
public synchronized void call() {
System.out.println("打电话");
}
}
结果: