每个进程(相当于应用程序)都有独立的代码和数据空间(内存),进程间的切换会有较大开销,一个进程包含1~n个线程。
线程同一类线程(相当于同一程序的多个窗口)共享代码和数据空间,每个线程都有独立的运行程序和程序计数器。
多进程操作系统能同时运行多个任务(程序)。
多线程同一程序中有多个顺序流在执行。
线程的生命周期 实现一个线程的三种方式 第一种方式 继承Thread类1.让一个类继承Thread类
public class A extends Thread{
//2.重写run()方法
public void run(){
for (int i = 0; i <=40 ; i++) {
//获取当前运行的线程名
String threadName=Thread.currentThread().getName();
System.out.println(threadName+":"+i);
}
}
public static void main(String[] args) {
A a1=new A();
A a2=new A();
//调用start()方法
a1.start();
a2.start();
}
}
1.为什么书写的是run()方法,调用的却是start方法?
答:只有调用了 start()方法,才会表现出多线程的特性,不同线程的 run() 方法里面的代码交替执行。如果直接调用run()方法是面向对象中的方法调用,只有一个线程main,不具备多线程的特性。
2.为什么调用的是start方法,执行的却是run方法?
答:start()方法是线程启动方法,使得线程处于就绪状态等待cpu,当获取到cpu资源后会调用run()方法,交替执行方法中的内容。
3.为什么a1的run方法未执行完毕,a2的run方法就执行了?
答:因为a1和a2是两个线程,会进行资源抢占,谁抢到cpu谁就获取cup资源信息,且每次执行结果都不同。
第二种方式 实现Runnable接口//创建线程的第二种方法
//①.实现Runnable接口
public class DemoB implements Runnable {
//②.重写run方法
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
public static void main(String[] args) {
//这个时候并不是新建状态,并不是一个线程对象
DemoB b1=new DemoB();
DemoB b2=new DemoB();
// 产生2个线程去包装这两个任务b1,b2
// 新建状态
Thread t1=new Thread(b1);
Thread t2=new Thread(b2);
t1.start();
t2.start();
}
}
第三种方式 实现Callable接口
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
//实现一个Callable接口
public class C implements Callable {
//重写call方法,有返回结果
int sum=0;
public Object call() throws Exception{
for (int i = 0; i <= 20; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
sum+=i;
}
return "1-20之和为:"+sum;
}
public static void main(String[] args) throws Exception{
C c1=new C();
C c2=new C();
FutureTask ft1=new FutureTask(c1);
FutureTask ft2=new FutureTask(c2);
Thread t1=new Thread(ft1);
Thread t2=new Thread(ft2);
t1.start();
t2.start();
Object result1=ft1.get();
Object result2=ft2.get();
System.out.println(result1);
System.out.println(result2);
}
}
sychronized关键字
同步锁,有两种使用范围
①方法中加锁,保证线程安全,一次只有一个线程进入
②代码块加锁:sychronized(obj){
//对一段代码块上锁,一次可以有多个线程进入
}
// synchronized关键字的使用场景 同步锁
public class DemoF {
private int count = 10;
// 对当前方法上锁的方式 保证线程安全 场景一
public synchronized void MethodA() {
if (count > 0) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "执行了递减操作,还剩" + (count--));
return;
}
} else {
System.out.println("count值必须大于0!");
}
}
private Object obj = new Object();
public void MethodB() {
System.out.println(Thread.currentThread().getName() + "开始执行递减操作....");
//同步代码块
synchronized (obj) {
if (count > 0) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "执行了递减操作,还剩" + (count--));
return;
}
} else {
System.out.println("count值必须大于0!");
}
}
}
public static void main(String[] args) {
DemoF f = new DemoF();
for (int i = 0; i < 4; i++) {
DemoF1 f1 = new DemoF1(f);
Thread t1 = new Thread(f1);
t1.start();
}
}
}
class DemoF1 implements Runnable {
private DemoF f;
public DemoF1(DemoF f) {
this.f = f;
}
public void run() {
for (int i = 0; i < 10; i++) {
f.MethodB();
}
}
}
死锁
两个或两个以上的进程中每一个都在等待其中另一个进程释放资源,导致无法向前推进,这种现象称为死锁。
ThreadLocal关键字本地线程,一个线程内部的存储类,可以在指定线程内存储数据,而且存储的数据只能在当前线程使用。
sleep、wait、yield、join方法 sleep()睡眠方法,在锁资源中使用,线程会进入阻塞状态,sleep睡眠结束后不会立即释放锁资源,其他线程仍然无法访问,线程由阻塞态--->就绪态,不会立即变为运行态,要等待获取cpu资源。
//通过sleep演示线程阻塞
public class DemoD {
public static void main(String[] args) {
DemoD1 d1=new DemoD1();
d1.start();
}
static class DemoD1 extends Thread{
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
// 让当前线程睡眠1s 单位是毫秒 线程从运行状态--->阻塞状态
} catch (InterruptedException e) {
e.printStackTrace();
}
// 1s之后 阻塞时间到了 阻塞状态--->就绪状态--->运行状态
}
}
}
}
wait()
让当前线程等待,也会让线程进入阻塞状态,是object类的一个方法,会释放锁资源,其他线程可以访问,wait方法只能在同步方法或同步代码块中使用,只能在有锁资源中使用。
wait()方法什么时候结束?
1.可以设置等待时间
2.通过notify方法唤醒等待的线程
public class DemoB {
public static void main(String[] args) {
DemoB3 a3 = new DemoB3();
DemoB2 a2 = new DemoB2(a3);
DemoB1 a1 = new DemoB1(a3);
Thread t1 = new Thread(a1);
Thread t2 = new Thread(a2);
//启动2个线程,让两个线程进入就绪态
t1.start();
t2.start();
}
}
class DemoB1 implements Runnable {
private DemoB3 a3;
public DemoB1(DemoB3 a3) {
this.a3 = a3;
}
public void run() {
a3.a();
}
}
class DemoB2 implements Runnable {
private DemoB3 a3;
public DemoB2(DemoB3 a3) {
this.a3 = a3;
}
public void run() {
a3.b();
}
}
class DemoB3 {
public synchronized void a() {
System.out.println("我是a方法,正在被" + Thread.currentThread().getName() + "线程执行");
try {
wait(1000);//让当前线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我的阻塞原因解除");
}
public synchronized void b() {
System.out.println("我是a方法,正在被" + Thread.currentThread().getName() + "线程执行");
try {
wait();//让当前线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我的阻塞原因解除");
}
public synchronized void c(){
notifyAll();//唤醒所有线程
}
}
yield()
让当前线程暂停一下,不释放锁资源,线程不会进入阻塞状态,暂停结束后线程继续运行,建议在锁资源中使用(实际上无法保证yield方法达到让步目的,因为让步的线程可能被线程调度再次选中)
public class DemoC {
public static void main(String[] args) {
DemoC3 c3 = new DemoC3();
DemoC2 c2 = new DemoC2(c3);
DemoC1 c1 = new DemoC1(c3);
Thread t1 = new Thread(c1);
Thread t2 = new Thread(c2);
//启动2个线程,让两个线程进入就绪态
t1.start();
t2.start();
}
}
class DemoC1 implements Runnable {
private DemoC3 c3;
public DemoC1(DemoC3 c3) {
this.c3 =c3;
}
public void run() {
c3.a();
}
}
class DemoC2 implements Runnable {
private DemoC3 c3;
public DemoC2(DemoC3 c3) {
this.c3 = c3;
}
public void run() {
c3.a();
}
}
class DemoC3 {
public void a() {
System.out.println("我是a方法,正在被" + Thread.currentThread().getName() + "线程执行");
Thread.yield();//让当前线程暂停一下
System.out.println("我的阻塞原因解除,继续执行"+Thread.currentThread().getName());
}
public synchronized void b() {
System.out.println("我是b方法,正在被" + Thread.currentThread().getName() + "线程执行");
Thread.yield();
System.out.println("我的阻塞原因解除,继续执行"+Thread.currentThread().getName());
}
}
join()
让路方法,等待调用join方法的线程结束后程序才能继续运行。
//join方法 让路方法 等待调用join方法的线程结束后 程序才能继续运行
public class DemoD {
private static final Object obj=new Object();
private static int count=0;//计数器
public static void main(String[] args) throws Exception{
DemoD1 d1=new DemoD1();
DemoD2 d2=new DemoD2();
Thread t1=new Thread(d1);
Thread t2=new Thread(d2);
t1.start();
t2.start();
//调用join方法的线程结束后 程序才能继续运行
t1.join();
t2.join();
System.out.println("结果是:"+count);
}
static class DemoD1 implements Runnable{
public void run(){
synchronized(obj){
System.out.println(Thread.currentThread().getName()+"准备执行");
for (int i = 0; i <10 ; i++) {
count++;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束执行");
}
}
}
static class DemoD2 implements Runnable{
public void run(){
synchronized (obj){
System.out.println(Thread.currentThread().getName()+"准备执行");
for (int i = 0; i <10 ; i++) {
count++;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束执行");
}
}
}
}
线程池
如果线程数量多且每个线程执行时间短,可以通过线程池实现复用。
单线程池池子中有且仅有一个线程,无论多少任务都由这一个线程处理
public class DemoF {
public static void main(String[] args) {
//产生了一个单线程的线程池
ExecutorService service= Executors.newSingleThreadExecutor();
//模拟了一百个任务
for (int i = 0; i <100 ; i++) {
DemoF1 f1=new DemoF1();
service.execute(f1);
}
}
}
class DemoF1 implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName()+"执行了任务!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
定长线程池(常用)
线程个数是固定的
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DemoG {
//产生了一个定长线程池 个数固定 四个
public static void main(String[] args) {
ExecutorService service= Executors.newFixedThreadPool(4);
for (int i = 0; i <100 ; i++) {
DemoG1 g1=new DemoG1();
service.execute(g1);
}
}
}
class DemoG1 implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName()+"执行了任务!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
可缓存线程池
public class DemoH {
public static void main(String[] args) {
//创建可缓存线程池 如果线程池长度超过处理需要,可灵活回收空闲线程和创建新线程 若无可回收,则创建新线程
ExecutorService service= Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
DemoH1 h1=new DemoH1();
service.execute(h1);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class DemoH1 implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName()+"执行了任务!");
}
}
定时器线程池
public class DemoI {
public static void main(String[] args) {
ScheduledExecutorService service= Executors.newScheduledThreadPool(4);
DemoI1 i1=new DemoI1();
//延迟5s后开始执行任务
//service.schedule(i1,5, TimeUnit.SECONDS);
//延迟5s后开始执行任务 并且每个1s后在执行一次
service.scheduleAtFixedRate(i1,5,1,TimeUnit.SECONDS);
}
}
class DemoI1 implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName()+"执行了任务!");
}
}
shutdown和shutdownNow的区别
shutdown会等待线程池中的任务执行完成后关闭线程池,并且不会接受新任务shutdownNow会给所有正在运行的线程发送中断信号,试图(不一定能立即关闭)中断任务的执行,然后关闭线程池
public class DemoJ {
public static void main(String[] args) {
a();
}
public static void a(){
ExecutorService service= Executors.newFixedThreadPool(2);
for (int i = 0; i <20 ; i++) {
DemoJ1 j=new DemoJ1();
service.execute(j);
}
service.shutdown();
try {
boolean b=service.awaitTermination(5, TimeUnit.SECONDS);
//判断当前线程池状态 true:正常终结 flase:没有关闭
System.out.println(b);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行了shutdown()方法");
}
public static void b(){
ExecutorService service= Executors.newFixedThreadPool(2);
for (int i = 0; i <20 ; i++) {
DemoJ1 j=new DemoJ1();
service.execute(j);
}
service.shutdownNow();
try {
boolean b=service.awaitTermination(3, TimeUnit.SECONDS);
System.out.println(b);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行了shutdownNow()方法");
}
}
class DemoJ1 implements Runnable{
public void run(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行了");
}
}
excecute()和submit()都是像线程池中提交任务excute针对的是Runnable()的任务,sumbit针对的是Callable的任务(有返回结果)
定时器---TimerTask
public class DemoK {
public static void main(String[] args) {
DemoK1 k1=new DemoK1();//产生了一个定时任务对象
Timer timer=new Timer();//负责执行定时任务的对象
// timer.schedule(k1,5000);//5s后开始执行任务
//timer.schedule(k1,5000,1000);//5s后开始执行任务,每隔1s执行一次
//在具体时间执行该任务
Date date=new Date(122,5,23,19,13,0);
timer.schedule(k1,date);
}
}
class DemoK1 extends TimerTask {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行了该方法!");
}
}
CountDownLatch 工具类
同步工具类 让一个或多个线程等待 直到其他线程执行完后才执行 类似join()方法
public class DemoL {
public static void main(String[] args) {
CountDownLatch cdl=new CountDownLatch(4);
for (int i = 0; i <4 ; i++) {
DemoL1 l1=new DemoL1(cdl);
Thread t1=new Thread(l1);
t1.start();
}
System.out.println("内容必须等待所有线程结束才执行");
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("你好,中国");
}
}
class DemoL1 implements Runnable{
private CountDownLatch cdl;
public DemoL1(CountDownLatch cdl) {
this.cdl = cdl;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行了!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束了!");
//标注线程结束了
cdl.countDown();
}
}


