1.进程和线程
1.1进程
进程是一个独立运作应用程序
1.独立性:
各个进程之间是互相独立的,互相不影响的
2.互斥行:
每个应用程序(软件)系统分配一个独立的端口号如果一个软件qq端口号 97 idea端口也叫97
写代码 Demo1 里面 main主函数 Demo1可以看成一个应用程序 就是一个进程
1.2线程
进程是由至少一个或者多个线程组成的
线程是进程最小的基本单位
线程的特性:
1.抢占式运行【重要】
给程序 分配CPU,按照时间片来执行,单位时间片抢占式执行的。随机抢占的
2.资源共享
同一个进程,有多个线程,这个多个线程是可以共享同一个数据的
Java程序:Demo1可以看成一个进程,
一个Java程序中有两个线程:
1.main 主线程
2.垃圾回收的线程
1.3并行和并发
并行:真正的同时执行
并发:同时发生,轮流交替执行
1.4创建线程的两种方式
Java虚拟机允许应用程序同时执行多个执行线程。
创建线程的第一种方式:( 继承Thread)
创建一个新的执行线程有两种方法。 一个是将一个类声明为Thread
的子类。 这个子类应该重写run
方法Thread
。 然后可以分配并启动子类的实例。
//1.一个是将一个类声明为`Thread`的子类
class MyThread1 extends Thread {
//2.重写run方法
@Override
public void run() {
//这个线程中干了打印100次的MyThread1线程:
for (int i = 0; i < 10000; i++) {
System.out.println("MyThread1线程:" + i);
}
}
}
class MyThread2 extends Thread {
@Override
public void run() {
//这个线程中干了打印100次的MyThread2线程:
for (int i = 0; i < 10000; i++) {
System.out.println("MyThread2线程:" + i);
}
}
}
public class Demo1 {
public static void main(String[] args) {
//3.新建线程的实例
MyThread1 myThread1 = new MyThread1();
//4.启动线程 启动
myThread1.start();
MyThread2 myThread2 = new MyThread2();
myThread2.start();
for (int i = 0; i < 10000; i++) {
System.out.println("主线程" + i);
}
}
}
创建线程的第二种创建方式:(实现Runnable接口)
另一种方法来创建一个线程是声明实现类Runnable
接口。 那个类然后实现了run
方法。 然后可以分配类的实例,在创建Thread
时作为参数传递,并启动。
//声明实现`Runnable`接口的类
class MyThread1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("MyThread1:" + i);
}
}
}
class MyThread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("MyThread2:" + i);
}
}
}
public class Demo1 {
public static void main(String[] args) {
MyThread1 myThread1 = new MyThread1();
MyThread2 myThread2 = new MyThread2();
//在创建`Thread`时作为参数传递并启动。
new Thread(myThread1).start();
new Thread(myThread2).start();
}
}
新建两个线程,一个线程打印99乘法表,另外一个线程打印直接三角形
class MyThread3 implements Runnable {
@Override
public void run() {
for (int i = 1; i < 10 ; i++) {
for (int j = 1; j <= i; j++) {
System.out.print("*");
}
System.out.println();
}
}
}
class MyThread4 implements Runnable {
@Override
public void run() {
for (int i = 1; i < 10; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "*" + i + "=" + i*j + "\t");
}
System.out.println();
}
}
}
public class Demo3 {
public static void main(String[] args) {
// 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。
new Thread(new MyThread3()).start();
new Thread(new MyThread4()).start();
}
}
1.5线程方法
构造方法:
Thread()
分配一个新的Thread对象 (第一种创建的形式)
Thread(Runnable target)
分配一个新的Thread对象 (第二种创建的形式)
Thread(Runnable target, String name)
分配一个新的Thread对象,并对这个线程起一个名字
方法:
static Thread | currentThread()返回对当前正在执行的线程对象的引用 |
---|---|
String | getName()返回此线程的名称 |
void | setName(String name)将此线程的名称更改为等于参数name |
class MyThread1 implements Runnable {
@Override
public void run() {
Thread thread = Thread.currentThread();
//Mythread1默认的额名字Thread-0
System.out.println(thread.getName());
}
}
class MyThread2 implements Runnable {
@Override
public void run() {
Thread thread = Thread.currentThread();
//Mythread1默认的额名字Thread-1
System.out.println(thread.getName());
}
}
public class Demo1 {
public static void main(String[] args) {
Thread thread = Thread.currentThread();//获取当前线程对象
System.out.println(thread.getName());//获取当前线程的名字 main
Thread thread1 = new Thread(new MyThread1(), "二狗");
//thread1.setName("狗蛋");
thread1.start();
new Thread(new MyThread2()).start();
}
}
线程下面的方法:
int | getPriority()返回此线程的优先级 |
---|---|
void | setPriority(int newPriority)更改此线程的优先级 |
class MyThread3 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("优先级是1的:" + i);
}
}
}
class MyThread4 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("优先级是10的:" + i);
}
}
}
public class Demo2 {
public static void main(String[] args) {
Thread thread = Thread.currentThread();
System.out.println(thread.getPriority());//获取当前线程的优先级 5
Thread thread1 = new Thread(new MyThread3());
thread1.setPriority(3);
thread1.start();
Thread thread2 = new Thread(new MyThread4());
thread2.setPriority(6);
thread2.start();
}
}
static void | sleep(long millis) 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性 |
---|---|
class MyThread3 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("优先级是1的:" + i);
}
}
}
class MyThread4 implements Runnable {
@Override
public void run() {
/**
* 为啥 Thread.sleep(20000); 只能try-catche
* run方法是重写的,重写的有严格限定
* public abstract void run();
*
*/
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10000; i++) {
System.out.println("优先级是10的:" + i);
}
}
}
public class Demo2 {
public static void main(String[] args) {
Thread thread = Thread.currentThread();
System.out.println(thread.getPriority());//获取当前线程的优先级 5
Thread thread1 = new Thread(new MyThread3());
thread1.setPriority(3);
thread1.start();
Thread thread2 = new Thread(new MyThread4());
thread2.setPriority(6);
thread2.start();
}
}
1.6线程同步和锁
当多个线程同时请求一个数据的时候,会导致数据不准确的情况。相互之间产生问题。容易出现线程安全的问题。
线程的同步真实的意思: 让你"排队",几个线程之间要排队。一个一个对共享资源进行操作,等一个结束以后,另外一个再进来操作。变量 是唯一的和准确的 可以加锁
同步方法:
public synchronized void eat () {
}
只能有一个线程进入到方法中,其他线程在方法的外面等待
同步代码块: 将一段代码放到synchronized 然后括起来。就会对这段代码加上锁。
synchronized (this) {
}
class SaleTicket implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
synchronized (this) {
if (ticket > 0) {
//线程2卖出了第72票
//线程2卖出了第71票
//线程1卖出了第100票
//线程1 线程2 都进入到if语句了
//
System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket +"票");
ticket--;
} else {
System.out.println("卖完了");
break;
}
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
//强调的是:多个线程操作同一个数据 ticket
SaleTicket saleTicket = new SaleTicket();
new Thread(saleTicket, "线程1").start();
new Thread(saleTicket, "线程2").start();
}
}
要求不能使用同步代码块来解锁,必须使用同步方法来加锁 来实现上面的案例
class SaleTicket1 implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
test();
if (ticket <= 0) {
break;
}
}
}
public synchronized void test() {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket +"票");
ticket--;
} else {
System.out.println("票已经买完了");
return;
}
}
}
public class Demo2 {
public static void main(String[] args) {
//强调的是:多个线程操作同一个数据 ticket
SaleTicket1 saleTicket = new SaleTicket1();
new Thread(saleTicket, "线程1").start();
new Thread(saleTicket, "线程2").start();
}
}
1.7Java中的锁
synchronized 被称为隐式锁,会自动释放,是一个非公平的锁
Lock锁 被称为显示锁
他们两个锁都可以解决线程同步的问题。但是synchronized 更加强大,更加粒度化。更加灵活。
一般开发的时候用synchronized
Lock是一个接口,实现ReentrantLock
有两个重要方法:
lock();
unlock();
class SaleTicket1 implements Runnable {
private int ticket = 100;
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try{
lock.lock();
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "票");
ticket--;
} else {
System.out.println("票已经买完了");
break;
}
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
}
public class Demo2 {
public static void main(String[] args) {
//强调的是:多个线程操作同一个数据 ticket
SaleTicket1 saleTicket = new SaleTicket1();
new Thread(saleTicket, "线程1").start();
new Thread(saleTicket, "线程2").start();
}
}
1.8守护线程
守护线程是用来守护非守护线程的
class MyThread8 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("守护线程:" + i);
}
}
}
public class Demo3 {
public static void main(String[] args) {
Thread thread = Thread.currentThread();
System.out.println(thread.isDaemon());//false 非守护线程
// thread.setDaemon(true);//设置为守护线程
Thread thread1 = new Thread(new MyThread8());
//System.out.println(thread1.isDaemon());
thread1.setDaemon(true);
thread1.start();
for (int i = 0; i < 200; i++) {
System.out.println("主线程:" + i);
}
}
}
2.死锁
开发中禁止出现死锁
应用场景: 并发场景,多个线程。线程之间在共享数据的时候 是互不相让的
线程加锁为了线程安全,但是物极必反。
死锁是一种状态,当两个线程互相持有对象所需要的资源的时候,这两个线程又都不主动释放资源
就会导致死锁。代码无法正常执行。这两个线程就会僵持住
class DeadLock implements Runnable {
private boolean flag;//标记
private Object obj1;//对象1
private Object obj2;//对象2
public DeadLock(boolean flag, Object obj1, Object obj2) {
this.flag = flag;
this.obj1 = obj1;
this.obj2 = obj2;
}
@Override
public void run() {
if (flag) {//如果flag = true 让线程1执行这个if语句里面的代码
synchronized (obj1) {
System.out.println(Thread.currentThread().getName() + "拿到了obj1资源");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1执行了");
synchronized (obj2) {//想用obj2这个资源
System.out.println(Thread.currentThread().getName() + "拿到obj2资源");
}
}
}
if (!flag) {//如果flag=false 线程2 执行这个if语句里面的代码
synchronized (obj2) {
System.out.println(Thread.currentThread().getName() + "拿到了obj2资源");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2执行了");
synchronized (obj1) {
System.out.println(Thread.currentThread().getName() + "拿到obj1资源");
}
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
DeadLock deadLock1 = new DeadLock(true, obj1, obj2);
new Thread(deadLock1, "线程1").start();
DeadLock deadLock2 = new DeadLock(false, obj1, obj2);
new Thread(deadLock2, "线程1").start();
}
}
3.Object类下面的和线程有关的方法
public final void wait()
throws InterruptedException
导致当前线程等待,知道另一个线程调用该对象的notify()
方法或notifyAll()
方法
总结: 至少两个线程,对象.wait(),那么当前线程就会等待
//为啥写Message这个类? wait方法 对象.wait(); 创建Message对象
//
class Message {
private String message;//信息
public Message(String message) {
this.message = message;
}
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
//线程类 等待线程
class WaitThread implements Runnable {
private Message message;
public WaitThread(Message message) {
this.message = message;
}
//等待线程抢到了
//等待线程睡了5秒 然后唤醒线程执行。 synchronized (message)
//message 对象从等待池中国去取的,结果发现没有 阻塞
//回到等待线程睡醒了以后开始 wait等待
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + "正在等待中....");
synchronized (message) {
try {
//当调用wait方法的时候,会自动释放锁,并将对象放到等待池中,让唤醒线程锁来操作这个对象
//
message.wait();//代码走到这一步 当前线程会等待!!!
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name +"被唤醒!!!Line45行的");
System.out.println(message.getMessage());
}
}
}
//唤醒线程
class NotifyThread implements Runnable {
private Message message;
public NotifyThread(Message message ) {
this.message = message;
}
@Override public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("唤醒线程已经执行");
synchronized (message) {
message.setMessage("我是修改之后的message对象");
//message.notify();
message.notifyAll();
}
}
}
public class Demo1 {
public static void main(String[] args) {
Message message = new Message("我是message对象");
WaitThread waitThread = new WaitThread(message);
WaitThread waitThread1 = new WaitThread(message);
NotifyThread notifyThread = new NotifyThread(message);
new Thread(waitThread1, "wait2线程").start();
new Thread(waitThread, "wait1线程").start();
new Thread(notifyThread, "notify线程").start();
}
}
4.线程的生命周期
1.线程的创建启动 start()
2.线程可运行状态 抢占 等待cpu
3.线程运行状态 抢占 和执行
4.线程的阻塞 wait sleep 锁
5.线程的消亡 destroy
5.join方法
作用:让父线程等待,一直等到子线程结束以后,父线程才会执行。
join方法实例:
class MyThread1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName() +":" + i);
}
}
}
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new MyThread1(), "子线程");
thread.start();
thread.join();//主线程等待 子线程先执行,
for (int i = 0; i < 1000; i++) {
System.out.println("主线程:" + i);
}
}
}
class FatherThread implements Runnable {
@Override
public void run() {
//在fathe线程去启动儿子线程
Thread thread = new Thread(new SonThread());
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 100; i++) {
System.out.println("父线程:" + i);
}
}
}
class SonThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("儿子线程:" + i);
}
}
}
public class Demo2 {
public static void main(String[] args) {
new Thread(new FatherThread()).start();
}
}
6.生产者消费者模式
生产线程负责生产,消费线程负责消费。
生产线程和消费线程要达到均衡。
这是一种特殊的业务需求,在这种特殊的情况下需要使用wait方法和notify方法
//为啥要写这个类 商品类
class Goods {
private String name;//商品的名字
private double price;//商品的价格
private boolean isProduct;//商品是否需要生产
//true需要生产 false 不需要生产
public Goods(String name, double price, boolean isProduct) {
this.name = name;
this.price = price;
this.isProduct = isProduct;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public boolean isProduct() {
return isProduct;
}
public void setProduct(boolean product) {
isProduct = product;
}
}
class Customer implements Runnable {//消费者线程
private Goods goods;
public Customer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
//消费者一直消费 生产者一直生产
while (true) {
synchronized (goods) {
//需要一直消费 判断商品是否有无
// //true需要生产 false 不需要生产
if (!goods.isProduct()) {
//不需要生产直接购买的
System.out.println("消费者购买:" + goods.getName() + ",价格为:"+ goods.getPrice());
//购买完以后,商品没了,商品标记为true
goods.setProduct(true);
//唤醒生产者 让其生产
goods.notify();
} else {
//需要生产 消费者线程等待
try {
goods.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
class Productor implements Runnable {//生产者线程
private Goods goods;
public Productor(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
int count = 0;
while (true) {
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (goods) {
// true需要生产 false 不需要生产
if (goods.isProduct()) {//true
//造车,如果是奇数的话,造玛莎拉蒂 如果是偶数的话,造劳斯莱斯
if (count % 2 == 0) {
//偶数
goods.setName("劳斯莱斯");
goods.setPrice(8.9);
} else {
//奇数
goods.setName("玛莎拉蒂");
goods.setPrice(7.6);
}
//生产者生产者完以后,将isProcut标记为
goods.setProduct(false);
System.out.println("生产者生产了:" + goods.getName() + ",价格为:" + goods.getPrice());
count++;
//生产者生产完以后 唤醒消费者。
goods.notify();
} else{
//不需要生产的
try {
goods.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
Goods goods = new Goods("红旗", 9.9, false);
Customer customer = new Customer(goods);
Productor productor = new Productor(goods);
new Thread(customer).start();
new Thread(productor).start();
}
}