网站首页 > 精选教程 正文
多线程技术概述
每个线程都有自己的栈空间,并用一份堆内存
1.同步和异步
同步:排队执行,效率低但是安全.
异步:同时执行,效率高但是数据不安全.
2.并发与并行
并发:指两个或多个时间在同一个时间段内发生.
并行:指两个或多个时间在同一时刻发生(同时发生)
3.执行步骤,有利于理解线程时用来做什么的
public class Test {
public static void main(String[] args) throws InterruptedException {
//1.创建一个任务对象
Xiancheng x1 = new Xiancheng();
//2.创建一个线程,并为其分配一个任务
Thread t = new Thread(x1);
//3.执行这个线程
t.start();
}
}
4.多用Runnable
5.线程对象可以打标记
package com.kkb;
public class Demo01_ThreadInterrupt {
public static void main(String[] args) {
Thread t = new Thread(new MyThings());
t.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t.interrupt();//给线程添加标记
}
}
class MyThings implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {//中断异常-->>如果这个事物正在执行的线程有了中断标记,那么就进入到catch块中
//System.out.println("虽然我添加了标记来到了这里,但是,你没有让我死亡哈哈哈哈");
//加上return资源就释放了
System.out.println("添加了interrupt标记,后面返回return,我结束了");
return;
}
}
}
}
6.守护线程
线程:分为守护线程和用户线程
用户线程:当一个进程不包含任何的存货线程时,进程结束
守护线程:守护用户的线程,当最后一个用户线程结束时,所有守护线程自动死亡
package com.kkb;
public class Demo01_ThreadInterrupt {
public static void main(String[] args) {
Thread t = new Thread(new MyThings());
t.setDaemon(true);//设置t为守护线程,当这个应用(进程中最后一个用户线程死亡的时候,守护线程自动死亡)
t.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// t.interrupt();//给线程添加标记
}
}
class MyThings implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {//中断异常-->>如果这个事物正在执行的线程有了中断标记,那么就进入到catch块中
//System.out.println("虽然我添加了标记来到了这里,但是,你没有让我死亡哈哈哈哈");
//加上return资源就释放了
System.out.println("添加了interrupt标记,后面返回return,我结束了");
return;
}
}
}
}
7.线程安全问题
概述:
* 为什么会导致线程不安全:
* 首先假定一种情况:当事物中余票为1时,三个线程进入来买票
* 1.A线程:看到conut>0,进入,正在出票的时候,count还没来得及做数据的变更操作
* 2.B线程:这个时候,B也进来了,因为conut还没有变更
* .....
* 这就是多线程,进入产生时间偏的问题-->>这里为了更好的模拟实际中的放票状态,就引入了一个Thread.sleep,使线程进行休眠的操作
package com.kkb;
/**
* 为什么会导致线程不安全:
* 首先假定一种情况:当事物中余票为1时,三个线程进入来买票
* 1.A线程:看到conut>0,进入,正在出票的时候,count还没来得及做数据的变更操作
* 2.B线程:这个时候,B也进来了,因为conut还没有变更
* .....
* 这就是多线程,进入产生时间偏的问题-->>这里为了更好的模拟实际中的放票状态,就引入了一个Thread.sleep,使线程进行休眠的操作
*
*/
public class UnSafe {
public static void main(String[] args) {
Runnable r = new Ticket();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
Thread t3 = new Thread(r);
t1.start();
t2.start();
t3.start();
}
static class Ticket implements Runnable{
private int conut = 10;
@Override
public void run() {
while (conut > 0){
System.out.println("正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
conut--;
System.out.println("余票:"+conut);
}
}
}
}
8.synchronized锁
注意:看同一把锁!!!!
同步代码块和同步方法都是隐式锁
1.同步代码块
package com.kkb;
/**
* 所谓上锁:就是在一个线程正在执行任务时,其他的对象只能在外面排队,因为这个事物现在的情况对外是不开放的
* 指定事物中的一个锁对象,在一个线程进入时,这个对象就会被标记上一把锁
* 要看同一把锁
*/
public class Safe_Synchronized {
public static void main(String[] args) {
Runnable r = new Ticket();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
Thread t3 = new Thread(r);
t1.start();
t2.start();
t3.start();
}
static class Ticket implements Runnable{
private int conut = 10;
private Object o = new Object();
//注意这里的o为了保证这个事物中存在一个可以上锁的对象
@Override
public void run() {
while (true) {
synchronized (o) {
if (conut > 0) {
System.out.println(Thread.currentThread().getName() + "正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
conut--;
System.out.println("余票:" + conut);
}else {
break;
}
}
}
}
}
}
2.设计为同步方法
* 注意这里面锁方法的时候,锁的对象就是这个方法饿地址上加锁,一个一个进入此方法
* 我们打印出来的this就是:com.kkb.Safe_Synchronized_To_method$Ticket@3694916f
* 这个方法的地址
只需要在这个方法上加上synchronized进行标志
package com.kkb;
/**
* 注意这里面锁方法的时候,锁的对象就是这个方法饿地址上加锁,一个一个进入此方法
* 我们打印出来的this就是:com.kkb.Safe_Synchronized_To_method$Ticket@3694916f
* 这个方法的地址
*/
public class Safe_Synchronized_To_method {
public static void main(String[] args) {
Runnable r = new Ticket();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
Thread t3 = new Thread(r);
t1.start();
t2.start();
t3.start();
}
static class Ticket implements Runnable{
private int conut = 10;
// private Object o = new Object();
//不需要这个对象了
//因为锁方法的时候锁的其实就是this,这个save方法的this
//注意这里的o为了保证这个事物中存在一个可以上锁的对象
//com.kkb.Safe_Synchronized_To_method$Ticket@3694916f
@Override
public void run() {
while (true) {
boolean sale = sale();
if (!sale){//如果没票了就结束
break;
}
}
}
public synchronized boolean sale(){
if (conut > 0) {
System.out.println(Thread.currentThread().getName() + "正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
conut--;
System.out.println("余票:" + conut);
System.out.println(this);
}else {
return false;
}
return true;
}
}
}
3.显示锁
Lock l = new ReentrantLock();
package com.kkb;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
*
*/
public class Safe_Synchronized_Lock {
public static void main(String[] args) {
Runnable r = new Ticket();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
Thread t3 = new Thread(r);
t1.start();
t2.start();
t3.start();
}
static class Ticket implements Runnable{
private int conut = 10;
//给一把显式锁
private Lock l = new ReentrantLock();//Lock锁接口的实现类
@Override
public void run() {
while (true) {
//每次一个线程进入就会加上一个锁,其他线程无法进入
l.lock();//加锁
boolean sale = sale();
l.unlock();//解锁
if (!sale){//如果没票了就结束
break;
}
}
}
public boolean sale(){
if (conut > 0) {
System.out.println(Thread.currentThread().getName() + "正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
conut--;
System.out.println("余票:" + conut);
}else {
return false;
}
return true;
}
}
}
4.公平锁和不公平锁
就是在声明显式锁的时候加上一个true.
排队一个一个进,不会出现线程争先恐后的,谁抢到就是谁的
Lock l = new ReentrantLock(true);
Thread-0正在准备卖票
余票:9
Thread-1正在准备卖票
余票:8
Thread-2正在准备卖票
余票:7
Thread-0正在准备卖票
余票:6
Thread-1正在准备卖票
余票:5
Thread-2正在准备卖票
余票:4
Thread-0正在准备卖票
余票:3
Thread-1正在准备卖票
余票:2
Thread-2正在准备卖票
余票:1
Thread-0正在准备卖票
余票:0
9.多线程交互问题
线程的wait和线程的唤醒notifyAll
再引入一个变量交替执行
10.线程池
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁的船舰线程和销毁线程需要时间.线程池就是一个可以容纳多个线程的容器,池中的线程可以反复的使用,省区了频繁创建线程对象的操作,节省了大量的时间和资源.
1.创建线程
2.创建任务
3.执行任务
4.关闭线程
1.缓存线程池
2.定长线程池
3.单线程池
4.周期定长线程池
- 上一篇: Java 爬虫遇上数据异步加载,试试这两种办法
- 下一篇: java:举例说明继承的概念
猜你喜欢
- 2024-11-27 Java 爬虫遇上数据异步加载,试试这两种办法
- 2024-11-27 Java 17 多线程的同步和异步synchronized关键字
- 2024-11-27 java异步编程产生的原因
- 2024-11-27 Java:了解Java中的异步套接字通道
- 2024-11-27 Java面试常见问题:阻塞与非阻塞,同步与异步
- 2024-11-27 parseq-让java异步并发编程更简单
- 2024-11-27 Java异步记录日志-2022新项目
- 2024-11-27 Java异步编程实战:基于JDK中的Future实现异步编程
- 2024-11-27 Java8异步编程就是拽的不行
- 2024-11-27 Java异步任务优化CompletionService
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)