Thread

Thread
1.并行与并发

并行:在某一个时间点内同时完成两件或多件事情。

并发:在某一个时间段内同时完成两件或多件事情。

2.进程与线程

进程:在内存中运行的应用程序,每一个进程有独立的运行空间,例如,windows中,xx.exe就代表了一个进程。

为什么要发明线程?

1、程序的内部只能完成单一任务

2、进程和进程之间的通讯很麻烦

线程:线程就是应用程序中的执行任务的单元。

一个进程可以并发的执行多条线程。

JAVA中,每一个JAVA程序就是一个进程,至少有两个线程(main线程–主线程、gc线程(垃圾收集))

换句话说,进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能。

但是要注意,一个进程虽然包括多个线程,但是这些线程是共同享有进程占有的资源和地址空间的。进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位。

用进程来对应一个程序,每个进程对应一定的内存地址空间,并且只能使用它自己的内存空间,各个进程间互不干扰。并且进程保存了程序每个时刻的运行状态,这样就为进程切换提供了可能。当进程暂时时,它会保存当前进程的状态(比如进程标识、进程的使用的资源等),在下一次重新切换回来时,便根据之前保存的状态进行恢复,然后继续执行。

3.多线程与多进程

多进程:可以让操作系统同时(宏观意义上)执行多个程序

多线程:在同一进程中同时去运行多个任务

多线程的优势:快

例子:LOL、行车道、多线程多任务断点下载

在java中创建进程:可以,很罕见,Runtime。

4.在java中如何创建线程:

1、继承Thread类;

线程类:只有Thread类或者Thread类的子类

(1)写个类A继承java.Lang.Thread类;

(2)在类A中重写Thread中的run()方法;

(3)在run()中写需要执行的操作,run()里面的代码—线程执行体;

(4)在main方法中,启动线程–创建线程对象,调用start()方法。

A a=new ();

a.start();

不是调用run(),如果调run,好比是对象调方法,

程序中还是只有一条主线程。

class Game extends Thread{

@Override

public void run() {

// TODO Auto-generated method stub

//super.run();

for (int i = 0; i < 50; i++) {

try{

sleep(10);

}catch(InterruptedException e){

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("playing game "+i);

}

}

}

2、实现Runnable接口:

(1)写个类A实现Runnable接口;类A不是线程类。

(2)覆盖接口中的run方法

(3)在run()中写需要执行的操作,run()里面的代码—线程执行体

(4 )在main方法中,启动线程–创建线程对象,调用start()方法。

创建线程类对象:

Thread thread=new Thread(new A());

启动线程:

a.start();

Thread(Runnable target):分配新的Thread对象,可以将一个Runnable接口的实例化对象作为参数去实例化Thread对象。

一个类实现了Runnable接口就必须用Thread类中的方法来启动多线程。

new Thread(new Runnable(){

@Override

public void run() {

// TODO Auto-generated method stub

//super.run();

for (int i=0;i<50;i++) {

try{

Thread.sleep(10);

}catch(InterruptedException e){

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("playing game: "+i);

}

}

}).start();

3 、通过匿名内部类实现:在某一个对象只是用一次的时候会出现

new Thread(){

public void run(){

for(int i=0;i<50;i++){

try{

Thread.sleep(10);

}catch(InterruptedException e)

{

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("playing game: "+i);

}

};

}.start();

public static native Thread currentThread();Returns a reference to the currently executing thread object.

继承Thread和实现Runnable区别?

1、java中是单继承,多实现;

2、继承Thread会导致每个线程都有自己的数据(将需要共享的数据添加static,也可以做到);实现Runnable接口可以共享一个数据;

3、起名字和获取名字的时候有区别

吃苹果出现了问题:

1、出现了多个同学同时吃一个苹果

2、出现了不该出现的苹果编号(0,-1,-2)

3、乱序

原因就是线程不同步(线程不安全),多条线程同时执行了一段代码

线程要保证原子性:最小的执行单位

线程同步:(处理线程不同步)

1、同步代码块

synchronized (同步锁) { 被同步的代码    }

java中,允许任何对象作为锁对象,一般我们会把当前线程并发访问的资源作为锁对象。最多只允许一个线程拥有锁对象,谁拿到锁对象,谁就能执行同步代码块,其他人只能等着。

This:static在类加载的时候就加载,此时还没有类对象,所以还没有this,所以this不是在哪度可以作为锁对象的(类方法中可以)

2、同步方法

同步方法中的代码都是同步代码,在方法前面加了一个synchronized关键字

同步方法中也有锁,只不过不用我们设置:

非static方法:用this

static用当前方法所在类的字节码对象即Class<?>。

编程准则:同步是解决共享机制的有效手段,虽然同步解决了线程安全的问题,但是效率低,所以尽可能的减少同步代码中的代码,等于降低了其他对象的等待时间,提高了效率。(同步代码块中包含尽可能少的操作,使得一个线程能尽快释放锁,减少其他线程等待锁的时间。)

3. 锁机制(Lock)

Lock是一个接口,实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作。但必须手动上锁和释放锁。

lock():获取锁     unloc():释放锁

锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用try-finally/catch加以保护,以确保在必要时释放锁。

同步的弊端:

1. 效率低;

2. 容易产生死锁(尤其是在同步嵌套的情况下会出现):两个或多个线程在执行过程中,因争夺资源而产生的一种相互等待的现象。

线程调度:计算机通常只有一个CPU, 在任意时刻只能执行一条机器指令,每个线程只有获得CPU的使用权才能执行指令。所谓多线程的并发运行,其实是指从宏观上看,各个线程轮流获得CPU的使用权,分别执行各自的任务。(如果说电脑只有一个cpu,在同一时间点只能完成一个任务,每一个线程都需要拿到cpu的执行权才能执行。)在可运行池中,会有多个处于就绪状态的线程在等待CPU,Java虚拟机的一项任务就是负责线程的调度。线程的调度是指按照特定的机制为多个线程分配CPU的使用权。

有两种调度模型:

1、分时调度模型:让所有线程轮流获得CPU的使用权,并且平均分配每个线程占用CPU的时间片。

2、抢占式调度模型:优先让可运行池中优先级高的线程较多可能占用CPU(概率高),如果可运行池中线程的优先级相同,那么就随机选择一个线程,使其占用CPU。处于可运行状态的线程会一直运行,直至它不得不放弃CPU。Java虚拟机采用这种模式,可能会造成多线程的随机性。。

单例模式:这个类在内存中只能有一个实例存在(贪吃蛇中的蛇,枚举,工具类),单例模式有7种:饿汉式,懒汉式

私有构造器不能实例化。

调用唤醒和等待时,锁对象是任何一个对象,所以放在了Object类

中。

线程的死锁:A线程等待B线程持有的锁,而B线程正在等待A持有的锁.

解决方案:尽量保证每个线程访问变量的顺序。

案例:哲学家吃饭问题

线程通信:不同的线程执行不同的任务,如果这些任务之间有某种关系,线程之间必须能够通信,协调完成工作。

线程通信经典案例:生产者和消费者案例(做饭案例):

生产者:厨师

|

产品:食物

|

消费者:顾客

代码设计:

生产者——>共享数据——>消费者

存不存在多线程? 存在

有没有共享的资源?  有

问题:

1、数据不匹配

可能会看到: 包子  素

饺子  肉

包子  null

饺子  null

null   null

因为线程不同步。

解决方案:只要保证在生产和消费的同步就可以,即生产的时候不能消费,消费的时候不能生产(可以通过synchronized解决)

有没有多线程?有        有没有共享资源? 有

有没有多条语句同时操作共享数据? 有

2、同一个数据出现了多次问题,重复消费和重复生产,应该交替出现包子饺子包子饺子。

解决方案:生产者等消费者真的消费完了再生产下一个(等待和唤醒机制)。(生产者生产号产品之后,等待消费者消费;消费者消费之后再等待生产者生产)。

Object类中提供的用于线程通信的方法:等待-唤醒机制(注意:以下方法只能被同步监听锁对象来调用,否则报错。)

wait():执行该方法的线程对象释放同步锁,JVM把该线程放到等待池中,等待其他线程唤醒他。

notity():执行该方法的线程唤醒在等待池中的任意一条线程,把线程转入锁池中等待。

notityAll():执行该方法的线程唤醒等待池中的所有线程,把线程转入锁池中等待。

1、线程在java中有几种实现方案?

4种     Thread  Runnable  匿名内部类 Callable

2、启动一个线程用的是run还是start

start

3、sleep和wait的区别

sleep:sleep必须指定时间,并且不会释放锁。

wait:可以指定时间,也可以不指定时间,会释放锁

线程状态:新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)、死亡状态(Dead)

线程休眠:sleep(5000) 放弃CPU, 转到阻塞状态。当结束睡眠后,首先转到就绪状态,如有其它线程在运行,不一定运行,而是在可运行池中等待获得CPU。线程在睡眠时如果被中断,就会收到一个InterrupedException异常,线程跳到异常处理代码块。

加入线程(联合线程):join():等待该线程执行完毕,别的线程才能执行。

线程礼让:yield():你一次我一次

守护线程:setDaemon()将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。

调整线程优先级:优先级高的线程只能获得较多运行的概率,但是实际中不一定真的有效果。Thread类的setPriority(int)和getPriority()方法分别用来设置优先级和读取优先级。优先级用整数来表示,取值范围是1-10.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值