进程
是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间
线程
是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行. 一个进程最少有一个线程线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分 成若干个线程
同步与异步&并发与并行
同步:排队执行 , 效率低但是安全.
异步:同时执行 , 效率高但是数据不安全.
并发:指两个或多个事件在同一个时间段内发生
并行:指两个或多个事件在同一时刻发生(同时发生)
多线程实现方法
线程的创建方式有多种,其中直接继承Thread类并直接运行和实现Runnable接口并委线程以任务的方式两种最为常见
继承Thread
public class MyThreea extends Thread{
@Override
public void run() {
for (int i
=0;i
<5;i
++){
System
.out
.println(Thread
.currentThread().getName()+":"+i
);
}
}
}
main方法中使用调用
public static void main(String
[] args
) {
MyThreea myThreea
= new MyThreea();
myThreea
.start();
for (int i
=5;i
<10;i
++){
System
.out
.println(Thread
.currentThread().getName()+":"+i
);
}
}
运行结果:(若想看到main线程和Thread-0线程交叉执行结果,可加以sleep方式)
实现Runnable接口 Runnable是一个接口,需要通过implement实现
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i
=0;i
<5;i
++){
System
.out
.println(Thread
.currentThread().getName()+":"i
);
}
}
}
public static void main(String
[] args
) {
MyRunnable mr
= new MyRunnable();
Thread thread
= new Thread(mr
);
thread
.start();
for (int i
=5;i
<10;i
++){
System
.out
.println(Thread
.currentThread().getName()+":"i
);
}
}
运行结果:
* 多线程技术
* 实现Runnable 与是继承Thread相比有如下优势:
* 1.通过创建任务,然后给线程分配的方式来实现多线程,更适合多个线程同时执行相同人物的情况
* 2.可以避免单继承带来的局限性
* 3.任务与线程本身是分离的,提高了程序的健壮性
* 4.后续学习地线程池技术,接受Runnable类型的任务,不接受Thread类型的线程
线程休眠sleep
public static void main(String
[] args
) throws InterruptedException
{
for (int i
=0;i
<10;i
++){
System
.out
.println(i
);
Thread
.sleep(1000);
}
}
sleep方法有两种形式
1.sleep(long millis):导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。
2.sleep(long millis, int nanos):导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数加上指定的纳秒数,具体取决于系统定时器和调度程序的精度和准确性。
线程阻塞
线程阻塞指所有比较消耗时间的操作,不仅仅是线程休眠这种情况,比如读取文件、接收用户输入等也称为耗时操作。
简单理解就是,只要使线程非死亡等待都属于线程阻塞
线程的中断
public class ThreadInterrupt {
public static void main(String
[] args
) {
Thread t1
= new Thread(new MyRunnable());
t1
.start();
for (int i
=0;i
<5;i
++){
System
.out
.println(Thread
.currentThread().getName()+":"+i
);
try {
Thread
.sleep(300);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
}
t1
.interrupt();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
for (int i
=5;i
<10;i
++){
System
.out
.println(i
);
try {
Thread
.sleep(500);
} catch (InterruptedException e
) {
System
.out
.println("发现中断标价,线程自杀");
return;
}
}
}
}
}
运行结果:
守护线程
线程:分为守护线程和用户线程
用户线程:当一个进程不包含任何一个存活的用户线程时,进程结束
守护线程:守护用户线程,当最后要给用户结束时,所有守护线程自动死亡
守护线程生成:thread.setDaemon(true);
public static void main(String
[] args
) {
Thread t1
= new Thread(new Runnable() {
@Override
public void run() {
for (int i
=0;i
<5;i
++){
System
.out
.println(Thread
.currentThread().getName()+":"+i
);
try {
Thread
.sleep(500);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
}
}
});
System
.out
.println(t1
+":"+t1
.getState());
t1
.setDaemon(true);
t1
.start();
System
.out
.println(t1
+":"+t1
.getState());
for (int i
=5;i
<10;i
++){
System
.out
.println(Thread
.currentThread().getName()+":"+i
);
try {
Thread
.sleep(200);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
}
System
.out
.println(t1
.getName()+":"+t1
.getState());
}
运行截图:
线程安全问题
线程不安全:多个线程同时执行,争抢并操作同一个资源
public class ThreadSafety {
public static void main(String
[] args
) {
Runnable runnable
= new MyRunnable();
new Thread(runnable
).start();
new Thread(runnable
).start();
new Thread(runnable
).start();
}
static class MyRunnable implements Runnable{
private int count
= 10;
@Override
public void run() {
while (count
>0){
System
.out
.println("正在准备卖票");
try {
Thread
.sleep(1000);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
count
--;
System
.out
.println("出票成功,余票:"+count
);
}
}
}
}
运行结果:
出现原因:当count==1时,由于“卖票”时线程休眠1s,所以三个线程都成功判定条件进入while循环。
**
那怎么才能解决线程不安全呢?
Java提供了同步代码块、同步方法和Lock的子类ReentrantLock三种方式解决线程不安全问题
同步代码块:
格式:synchronized(锁对象){} 任何对象都可作为锁存在 必须看同一把锁
public class ThreadSafety3 {
public static void main(String
[] args
) {
Runnable runnable
= new MyRunnable();
new Thread(runnable
).start();
new Thread(runnable
).start();
new Thread(runnable
).start();
}
static class MyRunnable implements Runnable{
private int count
= 5;
private Object o
= new Object();
@Override
public void run() {
while (true){
synchronized (o
){
if (count
>0){
System
.out
.println("正在准备卖票");
try {
Thread
.sleep(1000);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
count
--;
System
.out
.println(Thread
.currentThread().getName()+"出票成功,余票:"+count
);
}else {
System
.out
.println(Thread
.currentThread().getName()+"发现票卖光了");
break;
}
}
}
}
}
}
运行结果:
同步方法
同步方法于同步代码块类似,只需在需要锁住的方法中添加synchronized修饰便可
public class ThreadSafety2 {
public static void main(String
[] args
) {
Runnable runnable
= new MyRunnable();
new Thread(runnable
).start();
new Thread(runnable
).start();
new Thread(runnable
).start();
}
static class MyRunnable implements Runnable{
private int count
= 10;
@Override
public void run() {
while (true){
boolean flag
= sale();
if (!flag
){
System
.out
.println(Thread
.currentThread().getName()+"发现票卖完啦");
break;
}
}
}
public synchronized boolean sale(){
if (count
>0){
System
.out
.println("正在准备卖票");
try {
Thread
.sleep(100);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
count
--;
System
.out
.println("出票成功,余票:"+count
);
return true;
}
return false;
}
}
}
运行结果:
ReentranLock
public class ThreadSafety1 {
public static void main(String
[] args
) {
Runnable runnable
= new MyRunnable();
new Thread(runnable
).start();
new Thread(runnable
).start();
new Thread(runnable
).start();
}
static class MyRunnable implements Runnable{
private int count
= 10;
private Lock lock
= new ReentrantLock(true);
@Override
public void run() {
while (true){
lock
.lock();
if (count
>0){
System
.out
.println("正在准备卖票");
try {
Thread
.sleep(100);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
count
--;
System
.out
.println(Thread
.currentThread().getName()+"出票成功,余票:"+count
);
}else {
System
.out
.println(Thread
.currentThread().getName()+"发现票卖完了");
break;
}
lock
.unlock();
}
}
}
}
运行结果:
公平锁与非公平锁
公平锁: 被锁起来的资源只需要线程排队获取
非公平锁: 被锁起来的资源需要各个线程抢占获取 Java默认锁方式都是不公平锁
线程死锁
线程死锁:是指两个或两个以上的线程互相持有对方所需要的资源,由于synchronized的特性,一个线程持有一个资源,或者说获得一个锁,在该线程释放这个锁之前,其它线程是获取不到这个锁的,而且会一直死等下去,因此这便造成了死锁。
死锁避免方法:不要在任何有可能导致锁产生的方法调用另一个需要产生锁的方法
死锁演示:
public class ThreadDeadLock {
public static void main(String
[] args
) throws InterruptedException
{
Culprit culprit
= new Culprit();
Police police
= new Police();
new MyThread(culprit
,police
).start();
culprit
.say(police
);
}
static class MyThread extends Thread{
private Culprit culprit
;
private Police police
;
public MyThread(Culprit culprit
,Police police
){
this.culprit
= culprit
;
this.police
= police
;
}
@Override
public void run() {
try {
police
.say(culprit
);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
}
}
static class Culprit{
public synchronized void say(Police p
) throws InterruptedException
{
System
.out
.println("罪犯:你放了我,我放了人质");
p
.fun();
}
public synchronized void fun(){
System
.out
.println("罪犯被放走了,罪犯也放了人质");
}
}
static class Police{
public synchronized void say(Culprit c
) throws InterruptedException
{
System
.out
.println("警察:你放了人质,我放了你");
c
.fun();
}
public synchronized void fun(){
System
.out
.println("警察救了人质,但是罪犯跑了");
}
}
}
运行结果:
线程的六种状态
线程状态。 线程可以处于以下状态之一:
- NEW 尚未启动的线程处于此状态。
- RUNNABLE 在Java虚拟机中执行的线程处于此状态。
- BLOCKED 被阻塞等待监视器锁定的线程处于此状态。
- WAITING 无限期等待另一个线程执行特定操作的线程处于此状态
- TIMED_WAITING 正在等待另一个线程执行最多指定等待时间的操作的线程处于此 状态。
- TERMINATED 已退出的线程处于此状态
线程在给定时间点只能处于一种状态。 这些状态是虚拟机状态,不反映任何操作系统线程状态
附一张多线程超经典图(这张图搞懂了,java多线程就懂了差不多了)
带返回值的线程Callable
java中第三种线程实现方式
import java
.util
.concurrent
.Callable
;
import java
.util
.concurrent
.ExecutionException
;
import java
.util
.concurrent
.FutureTask
;
public class CallableDemo {
public static void main(String
[] args
) throws ExecutionException
, InterruptedException
{
Callable
<Integer> c
= new MyCallable();
FutureTask
<Integer> task
= new FutureTask<>(c
);
new Thread(task
).start();
Integer j
= task
.get();
System
.out
.println("返回值内容:"+j
);
for (int i
=5;i
<10;i
++){
try {
Thread
.sleep(100);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
System
.out
.println(Thread
.currentThread().getName()+":"+i
);
}
}
static class MyCallable implements Callable{
@Override
public Object
call() throws Exception
{
for (int i
=0;i
<5;i
++){
try {
Thread
.sleep(100);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
System
.out
.println(Thread
.currentThread().getName()+":"+i
);
}
return 100;
}
}
}
运行截图:
线程池
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率因为频繁创建线程和销毁线程需要时间.
线程池就是一个容纳多个线程的容器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。
缓存线程池
public class CacheThreadPool {
public static void main(String
[] args
) {
ExecutorService service
= Executors
.newCachedThreadPool();
service
.execute(new Runnable() {
@Override
public void run() {
System
.out
.println(Thread
.currentThread().getName()+"锄禾日当午");
}
});
service
.execute(new Runnable() {
@Override
public void run() {
System
.out
.println(Thread
.currentThread().getName()+"锄禾日当午");
}
});
service
.execute(new Runnable() {
@Override
public void run() {
System
.out
.println(Thread
.currentThread().getName()+"锄禾日当午");
}
});
try {
Thread
.sleep(1000);
} catch (InterruptedException e
) {
}
service
.execute(new Runnable() {
@Override
public void run() {
System
.out
.println(Thread
.currentThread().getName()+"锄禾日当午");
}
});
}
}
定长线程池
public class FixThreadPool {
public static void main(String
[] args
) {
ExecutorService service
= Executors
.newFixedThreadPool(2);
service
.execute(new Runnable() {
@Override
public void run() {
System
.out
.println(Thread
.currentThread().getName()+"锄禾日当午");
try {
Thread
.sleep(3000);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
}
});
service
.execute(new Runnable() {
@Override
public void run() {
System
.out
.println(Thread
.currentThread().getName()+"锄禾日当午");
try {
Thread
.sleep(3000);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
}
});
service
.execute(new Runnable() {
@Override
public void run() {
System
.out
.println(Thread
.currentThread().getName()+"锄禾日当午");
}
});
}
}
单线程线程池
public class SingleThreadPool {
public static void main(String
[] args
) {
ExecutorService service
= Executors
.newSingleThreadExecutor();
service
.execute(new Runnable() {
@Override
public void run() {
System
.out
.println(Thread
.currentThread().getName()+"锄禾日当午");
}
});
service
.execute(new Runnable() {
@Override
public void run() {
System
.out
.println(Thread
.currentThread().getName()+"锄禾日当午");
}
});
service
.execute(new Runnable() {
@Override
public void run() {
System
.out
.println(Thread
.currentThread().getName()+"锄禾日当午");
}
});
}
}
周期定长线程池
public class CycleThreadPool {
public static void main(String
[] args
) {
ScheduledExecutorService service
= Executors
.newScheduledThreadPool(2);
service
.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System
.out
.println("旱地和下图");
}
},5,1,TimeUnit
.SECONDS
);
}
}