java 多线程笔记_Java多线程初学者笔记

线程是依赖于进程存在的,所以要想了解线程必须先了解什么是进程。

1.概念

进程:打开任务管理器,正在运行的程序都会出现进程,所以进程指的就是正在运行(进行)的程序

多进程:多个进程同时运行,比如计算机可以一边玩游戏一边听音乐

线程和多线程:在同一个进程内可以执行多个任务,而这每一个任务我就可以看成是一个线程,线程是程度的执行单元,执行路径,是程序使用CPU的最基本单位。如果程序有多条执行路径就叫做多线程

2.意义:

多进程:可以提高CPU的使用率

多线程:可以提高程序的使用率,程序的执行其实都是在抢CPU的资源,不能保证哪个线程会先抢到资源,所以线程的执行有随机性。

3.多线程的实现方案

A:继承Thread

B.实现Runnable接口

切记:run()方法里面的代码全部执行完毕,当前线程就会自动关闭销毁。

知道这一点以后要想关闭线程就知道怎么操作了

AAffA0nNPuCLAAAAAElFTkSuQmCC

4.线程的调度和优先级问题

A:线程的调度

a:分时调度

所有线程轮流使用CPU的使用权,平均分配每个线程的时间片

b:抢占式调度

优先让优先级高的线程使用CPU,优先级高的线程获取CPU时间片的几率相对高一些,如果线程的优先级相同,会随机选择一个。

java使用的是抢占式调度模型。

B:优先级

默认是5,范围是1-10

5.线程的控制(常见方法)

线程休眠(sleep)

加入线程(join)

礼让线程(yield)

守护线程(setDaemon)

中断线程(interrupt)

6.线程的生命周期

AAffA0nNPuCLAAAAAElFTkSuQmCC

7.多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)

A:是否有多线程环境

B:是否有共享数据

C:是否有多条语句操作共享数据

8.同步解决线程安全问题

同步的前提:1.多个线程 2.多个线程使用的是同一个锁对象

A:同步代码块

synchronized(对象) {

需要被同步的代码;

}

这里的锁对象可以是任意对象。

B:同步方法

把同步加在方法上。

这里的锁对象是this

C:静态同步方法

把同步加在方法上。

这里的锁对象是当前类的字节码文件对象(也就是类.class)

9.线程安全的类

通过源码查看到这些类里面的方法都加了同步锁,所以是线程安全的

A:StringBuffer

B:Vector

C:Hashtable

D:如何把一个线程不安全的集合类变成一个线程安全的集合类

用Collections工具类的方法即可。

10.线程死锁问题

是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象。如果出现了同步嵌套,就容易产生死锁问题。

11.线程之间的通信(生产者与消费者的案例)

线程之间的通信指的是针对同一个资源的操作有不同种类的线程

举例:生产者做包子,消费者买包子。

此案例加入了两点优化:

A:等待唤醒机制

1.针对的是锁对象,所以锁对象是谁,就用谁调用wait和notify

2.wait,线程等待,释放锁

3.notify,正在等待的线程被唤醒

B:将同步锁代码块改成同步锁方法

很多人初级接触多线程时,会习惯把wait()和notify()放在run()方法里,一定 要谨记,这两个方法属于某个对象,应在对象所在的类方法中定义它,然后run中去调用它。另外wait()和notify()必须包括在synchronized代码块中。

package Thread.BaoZiPro;

//这是生产者类线程(生产包子)

public class Set implements Runnable {

private int i;

private Baozi bz;

public Set(Baozi bz) {

this.bz =bz;

}

@Override

public void run() {

while(true){

if(i%2==0){

bz.setNum(100, "糖包子");

}else{

bz.setNum(200, "肉包子");

}

i++;

}

}

}

package Thread.BaoZiPro;

//这是消费者类线程(购买包子)

public class Get implements Runnable {

private Baozi bz;

public Get(Baozi bz) {

this.bz =bz;

}

@Override

public void run() {

while(true){

bz.get();

}

}

}

package Thread.BaoZiPro;

//这是共享资源类

public class Baozi {

private int num;

private String type;

//设置一个标签判断是否有资源,默认值false

private boolean flag;

public synchronized void setNum(int num,String type) {

//如果flag=true,表示有包子

if(flag){

try {

this.wait();//生产者线程等待,并释放锁,等待被唤醒

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

//如果如果flag=true,表示没有包子,则生产包子

this.num = num;

this.type= type;

//并设置标签为true,提示有包子了

flag=true;

//唤醒正在等待的线程,也就是唤醒消费者线程

this.notify();

}

public synchronized void get() {

//如果!flag=true,也就是flag=flase,没有包子

if(!flag){

try {

this.wait();//消费者线程等待,并释放锁,等待被唤醒

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

//如果!flag=false,也就是flag=true,有包子,所以消费者购买

System.out.println(this.num+this.type);

//设置共享资源标签为false,表示包子买完了

flag=false;

//唤醒正在等待的线程,也就是唤醒生产者线程

this.notify();

}

}

package Thread.BaoZiPro;

//这是测试类

public class BaoziDemo {

public static void main(String[] args) {

Baozi bz=new Baozi();

Set set=new Set(bz);

Get get=new Get(bz);

Thread t1=new Thread(set);

Thread t2=new Thread(get);

t2.start();

t1.start();

}

}

12.线程组

线程组表示的多个线程的集合

1.创建一个线程租

ThreadGroup tG=new ThreadGroup(String name); name表示的该线程组的名称

2.设置一个线程所在的线程组

Thread t1=new Thread(tG, tg);

Thread t2=new Thread(tG,tg2);

这样就可把t1,t2两个线程放进线程组tG中

3.getThreadGroup 返回值是该线程所在线程组

4.getThreadGroup.getName返回的是该线程所在线程组的名字

13.线程池

Executors类包含了一些返回线程池的方法:

1.public static ExecutorService newCachedThreadPool() 带缓冲的线程池

2.public static ExecutorService newFixedThreadPool(int nThreads) 可重用固定线程数的线程池

3.public static ExecutorService newSingleThreadExecutor() 单个线程的Executor

调用这些方法会返回一个ExecutorService对象,该对象表示一个线程池。

线程池对象可以通过调用submit()方法来执行Runnable对象或者Callable对象代表的线程,相当于线程的创建并启动。

14.定时器

定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和TimerTask类来实现定义调度的功能

实现一个定时器的步骤:

1.创建定时器对象

2.创建一个任务

3.通过定时器调度任务

你可能感兴趣的:(java,多线程笔记)