进程
正在运行的程序,系统进行资源分配和调用的独立单位
线程:进程中的单个顺序控制流,是一条执行路径
单线程,多线程:一个进程有单个还是多个执行路径
多线程的实现方式1-继承Thread类
设置和获取线程名称
getName
setName
线程调度
1、分时调度模型
2、抢占式调度模型:优先让优先级高的线程使用CPU;(JAVA使用的方式)
返回优先级:
public final int getPriority():返回此线程的优先级。
public final void setPriority(int newPriority)
更改此线程的优先级。(默认是5,范围是1-10之间)
代码实例:
申明一个实现Thread接口的类
//继承Thread方法
public class duoxiancheng extends Thread {
@Override //重写run方法
public void run() {
for(int i = 0; i<100; i++){
System.out.println(getName()+":"+i);
}
运行类:
duoxiancheng d1 = new duoxiancheng();
duoxiancheng d2 = new duoxiancheng();
duoxiancheng d3 = new duoxiancheng();
d1.setName("shouhu1");
d2.setName("shouhu2");
d3.setName("laiha");
d1.start();
d2.start();
d3.start();
线程控制
setDeamon:将线程设置为守护线程(非主线程,副线程),如果主线程结束,当运行线程都是守护线程的时候,JAVA虚拟机退出
线程全生命周期
实现多线程方法2- 实现Runnable接口的方式
Runnable接口由任何类实现,其实例将由线程执行。
实现Runnable类Thread通过实例化一个Thread实例并将其自身作为目标来运行,而无需子类化Thread。
在大多数情况下,如果您仅计划覆盖run()方法,而不使用其他Thread方法,则应使用Runnable接口。
Thread(Runnable target, String name) 分配一个新的 Thread对象。
创建Thread类对象后,把线程对象作为构造方法的参数
代码实例:
实现runnabl接口:
public class runable implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++)
System.out.println(Thread.currentThread().getName()+":"+i);
}
主程序:
runable ra = new runable();
Thread tr1 = new Thread(ra,"meimei");
Thread tr2 = new Thread(ra,"keke");
tr1.start();
tr2.start();
Runnable相比Thread的好处
1、避免了JAVA单继承的局限性
2、适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好的体现了面向对象的思想。
多线程程序的安全
安全保证:把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行;JAVA提供了同步代码块的方式来解决
同步代码块
好处:用synchronized锁住到条语句块,可以解决多线程的数据安全问题;
弊端:当线程很多时,由于每个线程都会去判断同步的锁,会耗费不少资源;
private int tickets = 1000;
//设定同一把锁
private Object obj = new Object();
@Override
public void run() {
while (true) {
//锁线程
synchronized (obj) {
if(tickets>0) {
try {
//休息100MS便于其他线程抢到CPU
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets +"张票");
tickets --;
}
}
}
}
测试类:
runable ra = new runable();
Thread tr1 = new Thread(ra,"窗口一");
Thread tr2 = new Thread(ra,"窗口二");
Thread tr3 = new Thread(ra,"窗口三");
tr1.start();
tr2.start();
tr3.start();
同步方法
同步普通方法:
修饰符 synchronized 返回值类型 方法名(方法参数);
把synchronized关键字加到方法上;同步方法的锁对象是:this;
同步静态方法:
修饰符 static synchronized 返回值类型 方法名(方法参数);
同步静态方法的锁对象是:类名.class
线程安全的类
StringBuffer:
线程安全,可变的字符序列。
这个类已经被一个等同的类补充了,它被设计为使用一个线程, StringBuilder 。 通常应该使用StringBuilder类,因为它支持所有相同的操作,但它更快,因为它不执行同步。
Vector:
从Java 2平台v1.2开始,该类改进了List接口,使其成为Java Collections Framework的成员。 与新的集合实现不同, Vector被同步。 如果不需要线程安全的实现,建议使用ArrayList代替Vector
HashTable:
该类实现了一个哈希表,它将键映射到值。 任何非null对象都可以用作键值或值。
从Java 2平台v1.2开始,该类进行了改进,实现了Map接口,使其成为Java Collections Framework的成员。 与新的集合实现不同, Hashtable被同步。 如果不需要线程安全的实现,建议使用HashMap代替Hashtable
Lock锁
lock() 获得锁。
unlock() 释放锁。
Lock是接口不能直接被实例化,采用实现类ReentrackLock来实例化
代码实例:
线程类:
public class runable implements Runnable{
private int tickets = 100;
private Lock lock = new ReentrantLock();//实例化
@Override
public void run() {
while (true) {
try {
//用try finally的语法,try中有代码问题不影响锁操作
lock.lock();//加锁
{
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
tickets--;
}
}
}finally {
lock.unlock();//释放锁
}
}
}
}
测试类:
runable ra = new runable();
Thread tr1 = new Thread(ra,"窗口一");
Thread tr2 = new Thread(ra,"窗口二");
Thread tr3 = new Thread(ra,"窗口三");
tr1.start();
tr2.start();
tr3.start();
生产者和消费者模型
需要在同步里使用;等待和唤醒方法
wait后,需要其他线程继续操作的情况下,要进行notify或notifyAll唤醒操作