Java之Thread总结
一、概念
1、进程和线程的概念
进程:运行中的应用程序称为进程,拥有系统资源(cpu、内存)
线程:进程中的一段代码,一个进程中可以有多段代码。本身不拥有资源(共享所在进程的资源)
在java中,程序入口被自动创建为主线程,在主线程中可以创建多个子线程。
区别:
1、是否占有资源问题
2、创建或撤销一个进程所需要的开销比创建或撤销一个线程所需要的开销大
3、进程为重量级组件,线程为轻量级组件
多进程: 在操作系统中能同时运行多个任务(程序)
多线程: 在同一应用程序中有多个功能流同时执行
2、线程的主要特点
①、不能以一个文件名的方式独立存在在磁盘中;
②、不能单独执行,只有在进程启动后才可启动;
③、线程可以共享进程相同的内存(代码与数据)。
3、线程的主要用途
①、利用它可以完成重复性的工作(如实现动画、声音等的播放)。
②、从事一次性较费时的初始化工作(如网络连接、声音数据文件的加载)。
③、并发执行的运行效果(一个进程多个线程)以实现更复杂的功能
4、多线程(多个线程同时运行)程序的主要优点
①、可以减轻系统性能方面的瓶颈,因为可以并行操作;
②、提高CPU的处理器的效率,在多线程中,通过优先级管理,可以使重要的程序优先操作,提高了任务管理的灵活性;另一方面,在多CPU系统中,可以把不同的线程在不同的CPU中执行,真正做到同时处理多任务。
5、线程中常用的方法:
线程停止:
* public final void stop():强迫线程停止执行
* public void interrupt()中断线程。 表示中断线程一种状态
*
* join()
* yield()
* stop()
* setDeamon(boolean on):(用的多)
* sleep():线程睡眠 (用的多)
* wait():线程等待
*
6、三种实现创建线程的方法:
1)、继承Thread类,重写Run方法。
2)、实现Runnable接口,实现Run()。
3 )、实现Callablej接口,实现Call方法。
对比:接口对比继承来说:a、可以避免单继承的局限性。b、方便共享资源,同一份资源,多个代理访问。实现Callable接口可以获取返回值,可以抛出异常。
7、* 同步锁定对象:
* 1)可以Object类型以及任意的Java类型对象
* 2)如果一个方法进来之后是一个同步代码块,那么同步代码块可以演变成一个同步方法
* 3)如果是一个静态的同步方法,锁对象是当前类名class属性:类名.class (反射机制:获取一些类的字节码文件对象Class类对象)
*
*
*8、面试题:思考:
* wait()线程等待,notify(),唤醒单个线程,notifyAll():唤醒所有线程这三个方法为什么不定义到Thread类中呢而是定义在Object类中?
* 答:线程中会存在安全问题,并且解决线程安全问题使用的同步代码块或者同步方法来解决,同步代码块来解决线程安全问题,就存在同步锁对象,谁能代表同步锁对象(Object以及任意的Java类),把它定义到Object类中;
9、为了确保线程的安全,提出同步概念,所谓同步就是多个线程访问同一份资源。确保了资源安全,那么线程就安全了。synchronized–>保证同步,但是无法保证资源的唯一性,即线程访问的时候可能创造多个对象,所以又提出了单例设计模式。
那么当多个线程共享一份资源的时候,又会发生死锁现象(死锁:过多的额同步会造成死锁),所以解决的办法就是生产者消费者模式。
10、单例模式的两种方式
1)、懒汉式
A:构造器私有化
B:声明私有的静态属性
C:对外提供访问属性的静态方法,确保该对象存在
2)、饿汉式
A:构造器私有化
B:声明私有的静态属性,同时创建该对象
C:对外提供访问属性的静态方法
11、 使用同步机制的这种方式解决线程安全问题,但是不知道具体的锁对象在哪里添加,并且锁对象在哪里释放锁对象,对于这种情况Jdk5以后Java提供了一个更具体的锁对象:Lock
*
* Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作
*
* Lock是一个接口,所以它在使用的是 ReentrantLock子实现类
*
* public void lock()获取锁。
* public void unlock()试图释放此锁
*
*
12、生产者与消费者案例:
package com.sxt.thread.ProducterCustomer;
/** * s生产者 * @author 代虎 * */
public class Producter implements Runnable{
private Movie m;
public Producter(Movie m) {
super();
this.m = m;
}
@Override
public void run() {
for(int i=0;i<20;i++) {
if(i%2==0) {
m.play("左青龙");
}
else {
m.play("右白虎");
}
}
}
}
package com.sxt.thread.ProducterCustomer;
/**
* 消费者
* @author 代虎
*
*/
public class Customer implements Runnable{
private Movie m;
public Customer(Movie m) {
super();
this.m = m;
}
@Override
public void run() {
for(int i=0;i<20;i++) {
m.watch();
}
}
}
package com.sxt.thread.ProducterCustomer;
/** * 生产者与消费者模式 信号灯法 * @author 代虎 * */
public class Movie {
private String pic;
private boolean flag = true;
public synchronized void watch () {
if(flag) {
//消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//开始消费
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费了" + pic);
//消费完毕
//通知生产
this.notifyAll();
//消费停止
this.flag = true;
}
public synchronized void play(String pic) {
if(!flag) {
//生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//开始生产
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产了:" + pic);
//生产完毕
this.pic = pic;
//通知消费
this.notify();
this.flag = false;
}
}
package com.sxt.thread.ProducterCustomer;
/** * 测试 * @author 代虎 * */
public class Test {
public static void main(String[] args) {
//共同的资源
Movie m = new Movie();
//多线程
Producter p = new Producter(m);
Customer c = new Customer(m);
new Thread(p).start();
new Thread(c).start();
}
}
JavaSe中的定时器:
* Timer:
* 常用的几个方法:
* public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
* public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务
* public void schedule(TimerTask task, long delay, long period)
* 在多少毫秒后,执行任务,并且每个多少毫秒重复执行
* public void cancel()终止此计时器,丢弃所有当前已安排的任务
*