进程
线程
分时调度
抢占式调度
同步:排队执行,效率低但是安全。
异步:同步执行,效率高但是数据不安全。
并发:指两个或多个事件在同一个时间段内发生。
并行:指两个或多个事件在同一时刻发生(同时发生)。
构造器 | 描述 |
---|---|
Thread() | 分配新的Thread对象 |
Thread(Runnable target) | 分配新的Thread对象 |
Thread(Runnable target, String name) | 分配新的Thread对象 |
Thread(String name) | 分配新的Thread对象 |
变量和类型 | 方法 | 描述 |
---|---|---|
long | getId() | 返回此Thread的标识符 |
String | getName() | 返回此线程的名称 |
int | getPriority() | 返回此线程的优先级 |
void | run() | 如果此线程是使用单独的Runnable运行对象构造的,则调用该Runnable对象的run方法; 否则,此方法不执行任何操作并返回。 |
void | setName(String name) | 将此线程的名称更改为等于参数 name 。 |
void | setPriority(int newPriority) | 更改此线程的优先级。 |
static void | sleep(long millis) | 导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。 |
static void | sleep(long millis,int nanos) | 导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数加上指定的纳秒数,具体取决于系统定时器和调度程序的精度和准确性。 |
void | start() | 导致此线程开始执行;Java虚拟机调用此线程的run()方法 |
线程的生命周期存在五个状态:新建、就绪、运行、阻塞、终止。
新建:采用new语句创建完成
就绪:执行start后
运行:占用CPU时间
阻塞:执行了wait语句、执行了sleep语句和等待某个对象锁,等待输入的场合
终止:退出了run()语句
有两种方法可以创建新的执行线程。
一种是将类声明为Thread的子类,此子类可以覆盖类Thread的run方法,然后可以分配和启动子类的实例。
public class MyThread extends Thread {
/**
* run方法就是线程要执行的任务方法
*/
@Override
public void run(){
//这里的代码 就是一条新的执行路径
//这个执行路径的触发方式,不是调用run方法,而是通过thread对象的start()方法来启动任务
for(int i=0;i<10;i++){
System.out.println("锄禾日当午"+i);
}
}
}
public class Demo {
/**
* 多线程技术
*/
public static void main(String[] args) {
MyThread m = new MyThread();
m.start();
for(int i=0;i<10;i++) {
System.out.println("汗滴禾下土" + i);
}
}
}
运行结果有很多种情况,主要是看谁先抢到时间片,因为Java使用的是抢占式调度。
运行结果(其中一种情况):
使用匿名内部类,上方代码可改为:
public class Demo2 {
public static void main(String[] args) {
new Thread(){
@Override
public void run(){
for(int i=0;i<10;i++){
System.out.println("锄禾日当午"+i);
}
}
}.start();
for(int i=0;i<10;i++){
System.out.println("汗滴禾下土"+i);
}
}
}
另一种是声明一个实现Runnable接口的类,该类实现run方法,然后可以分配类的实例,在创建Thread时作为参数传递,然后启动。
/**
* 用于给线程进行执行的任务
*/
public class MyRunnabe implements Runnable {
@Override
public void run() {
//线程的任务
for(int i=0;i<10;i++){
System.out.println("床前明月光"+i);
}
}
}
public class Demo1 {
public static void main(String[] args) {
//实现Runnable
//1.创建一个任务对象
MyRunnabe r = new MyRunnabe();
//2.创建一个线程,并为其分配一个任务
Thread t = new Thread(r);
//3.执行这个线程
t.start();
for(int i=0;i<10;i++){
System.out.println("疑是地上霜"+i);
}
}
}
运行结果(其中一种情况):
实现Runnable 与 继承Thread相比有如下优势:
Thread.currentThread().getName()
public class Demo3 {
public static void main(String[] args) {
//获取线程的名称
System.out.println(Thread.currentThread().getName());
new Thread(new MyRunnable(),"这是一个线程名").start();
new Thread(new MyRunnable()).start();
new Thread(new MyRunnable()).start();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
}
运行结果为:
或
Thread.sleep(毫秒数)
public class Demo4 {
public static void main(String[] args) throws InterruptedException {
//线程的休眠 sleep
for(int i=0;i<10;i++){
System.out.println(i);
//每一秒输出i
Thread.sleep(1000);
}
}
}
public class Demo5 {
public static void main(String[] args) {
//线程的中断
//一个线程是一个独立的执行路径,它是否应该结束,应该由其自身决定,外部不能干涉线程死亡
Thread t1 = new Thread(new MyRunnable());
t1.start();
for(int i=1;i<=5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//给线程t1添加中断标记
t1.interrupt();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
for(int i=1;i<=10;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println("发现了中断标记,让这个线程自杀");
return;
}
}
}
}
}
运行结果(其中一种情况):
public class Demo6 {
public static void main(String[] args) {
//线程:分为守护线程和用户线程
//用户线程:当一个进程不包含任何的存活的用户线程时,进行结束。
//守护线程:守护用户线程的,当最后一个用户线程结束时,所有守护线程自动死亡。
//直接创建的线程都是用户线程
Thread t1 = new Thread(new MyRunnable());
//设置t1为守护线程,即使t1没有执行完,main的线程si掉后,它也跟着si掉
t1.setDaemon(true);
t1.start();
for(int i=1;i<=5;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class MyRunnable implements Runnable{
@Override
public void run() {
for(int i=1;i<=10;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("让线程自杀");
return;
}
}
}
}
}
public class Demo7 {
public static void main(String[] args) {
//线程不安全
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket 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 > 0为真,进入循环,然后线程休眠一秒,其他进程就可能在这一秒内判断count是否大于0,为真,进入循环。就出现多个进程count–,所以就出现有负数的情况,但这种情况是不符合常理的。
public class Demo8 {
/**
* 线程同步:synchronized
* @param args
*/
public static void main(String[] args) {
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//票数
private int count = 10;
private Object o = new Object();//只有一把锁,看同一把锁才能排队
@Override
public void run() {
while(true){
//Object o = new Object();//所有线程都有一把锁
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{
break;
}
}
}
}
}
}
运行结果(其中一种情况):
public class Demo9 {
/**
* 线程同步:synchronized
* @param args
*/
public static void main(String[] args) {
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//票数
private int count = 10;
private Object o = new Object();
@Override
public void run() {
while(true){
boolean flag = sale();
if(!flag){
break;
}
}
}
public synchronized boolean sale(){
if(count>0){
//卖票
System.out.println("正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"出票成功,余票为:"+count);
return true;
}
return false;
}
}
}
public class Demo10 {
/**
* 同步代码块 和 同步方法 都属于隐式锁
* 线程同步:Lock
* @param args
*/
public static void main(String[] args) {
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//票数
private int count = 10;
//显示锁:fair参数为true就表示是公平锁,先到先得
private Lock l = new ReentrantLock(true);
@Override
public void run() {
while(true){
l.lock();
if(count>0){
//卖票
System.out.println("正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"出票成功,余票为:"+count);
}else{
break;
}
l.unlock();
}
}
}
}
public class Demo11 {
public static void main(String[] args) {
//线程死锁
Culprit c = new Culprit();
Police p = new Police();
new MyThread(c,p).start();
c.say(p);
}
static class MyThread extends Thread{
private Culprit c;
private Police p;
public MyThread(Culprit c,Police p){
this.c = c;
this.p = p;
}
@Override
public void run(){
p.say(c);
}
}
//罪犯
static class Culprit{
public synchronized void say(Police p){
System.out.println("罪犯:你放了我,我放了人质");
p.fun();
}
public synchronized void fun(){
System.out.println("罪犯被放走了,罪犯也放了人质");
}
}
//警察
static class Police{
public synchronized void say(Culprit c){
System.out.println("警察:你放了人质,我放过你");
c.fun();
}
public synchronized void fun(){
System.out.println("警察救了人质,但是罪犯跑了");
}
}
}
运行结果:
public class Demo12 {
/**
* 多线程通信,生产者与消费者问题
* @param args
*/
public static void main(String[] args) {
Food f = new Food();
new Cook(f).start();
new Waiter(f).start();
}
//厨师
static class Cook extends Thread{
private Food f;
public Cook(Food f){
this.f = f;
}
@Override
public void run(){
for(int i=0;i<100;i++){
if(i%2==0){
f.setNameAndState("老干妈小米粥","香辣味");
}else{
f.setNameAndState("煎饼果子","甜辣味");
}
}
}
}
//服务生
static class Waiter extends Thread{
private Food f;
public Waiter(Food f){
this.f = f;
}
@Override
public void run(){
for(int i=0;i<100;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
f.get();
}
}
}
//食物
static class Food{
private String name;
private String taste;
//true表示可以生产 false表示可以消费
private boolean flag = true;
public synchronized void setNameAndState(String name,String taste){
if(flag){
this.name = name;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.taste = taste;
flag = false;
this.notifyAll();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void get(){
if(!flag){
System.out.println("服务员端走的菜的名称是"+name+",味道:"+taste);
flag = true;
this.notifyAll();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
运行结果:
不会出现菜品与味道不符,或者端走的菜品顺序错乱。
public class Demo13 {
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=0;i<10;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
static class MyCallable implements Callable<Integer>{
@Override
public Integer call() throws Exception {
//Thread.sleep(3000);
for(int i=0;i<10;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
return 100;
}
}
}
Runnable 与 Callable的相同点
Runnable 与 Callable的不同点
Callable获取返回值
Callalble接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间,线程就是一个容纳多个线程的容器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。
Java中的四种线程池:缓冲线程池、定长线程池、单线程线程池、周期性任务定长线程池
public class Demo14 {
/**
* 缓存线程池
* (长度无限制)
* 任务加入后的执行流程:
* 1.判断线程池是否有空闲线程
* 2.存在则使用
* 3.不存在,则创建线程并加入线程池,然后使用
*/
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) {
e.printStackTrace();
}
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
});
}
}
public class Demo15 {
/**
* 定长线程池
* (长度是指定的数值)
* 任务加入后的执行流程:
* 1.判断线程池是否存在空闲线程
* 2.存在则使用
* 3.不存在空闲线程,且线程未满的情况下,则创建线程,并放入线程池,然后使用
* 4.不存在空闲线程,且线程已满的情况下,则等待线程池存在空闲线程
*/
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 Demo16 {
/**
* 单线程线程池
* 执行流程:
* 1.判断线程池的单个线程是否空闲
* 2.空闲则使用
* 3.不空闲,则等待池中的单个线程空闲后使用
*/
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()+"锄禾日当午");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
});
}
}
public class Demo17 {
/**
* 周期任务定长线程池
* 执行流程:
* 1.判断线程池是否存在空闲线程
* 2.存在则使用
* 3.不存在空闲线程,且线程未满的情况下,则创建线程并放入线程池,然后使用
* 4.不存在空闲线程,且线程已满的情况下,则等待线程池存在空闲线程
* 周期性任务执行时:
* 定时执行,当某个时机触发时,自动执行某任务。
*/
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
/*service.schedule(new Runnable() {
@Override
public void run() {
System.out.println("锄禾日当午");
}
},5, TimeUnit.SECONDS);*/
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("锄禾日当午");
}
},5,1,TimeUnit.SECONDS);
}
}
public class Demo18 {
public static void main(String[] args) {
/**
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("锄禾日当午");
}
});
**/
//下方使用了Lambda表达式,运行结果等同于上方
Thread t = new Thread(() -> {
System.out.println("锄禾日当午");
});
t.start();
}
}