进程:应用程序的执行实例,有独立的内存空间和系统资源
线程:CPU调度和分派的基本单位,进程中执行运算的最小单位,可完成一个独立的顺序控制流程
进程包含线程,一个进程至少有一个线程。
什么是多线程?
1.如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为“多线程”
2.多个线程交替占用CPU资源,而非真正的并行执行
多线程好处
1.充分利用CPU的资源
2.简化编程模型
3.带来良好的用户体验
1.main()方法即为主线程入口
2.产生其他子线程的线程
3.必须最后完成执行,因为它执行各种关闭动作
1.定义线程
2.创建线程对象
3.启动线程
4.终止线程
Java提供了java.lang.Thread类支持多线程编程
步骤:
1.定义MyThread类继承Thread类
2.重写run()方法,编写线程执行体
3.创建线程对象,调用start()方法启动线程
//第一步:创建MyThread类继承Thread
public class MyThread extends Thread{
//第二步:重写Thread中的run方法
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"-"+i);
}
}
}
public class MyThreadTest {
public static void main(String[] args) {
//第三步:创建线程类对象
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
mt1.setName("线程A");
mt2.setName("线程B");
//mt1.run( );
//启动线程要使用strart()方法来启动线程,如果通过线程对象直接调用run()方法,
//那是由主线程来调用的,不是多现成的实现方式
mt1.start();
mt2.start();
}
/*
*多线程并不是真正意义上的并行执行,而是多个线程交替性抢占CPU资源,
*谁获取了CPU资源就执行谁*在执行过程中,有可能丢失CPU资源,
*被另外一个线程执行,所以会出现交替执行的现象
*
***/
}
Runnable接口:
实现java.lang.Runnable接口
步骤:
1.定义MyRunnable类
2.实现Runnable接口实现run()方法,编写线程执行体
3.创建线程对象,调用start()方法启动线程
//1.定义MyRunnable类
public class MyRunnable implements Runnable{
//2.实现Runnable接口实现run()方法,编写线程执行体
@Override
public void run() {
for(int i =1;i<=10;i++){
System.out.println( Thread.currentThread( ).getName()+" :"+i);
}
}
}
public class MyRunnableTest {
public static void main(String[] args) {
// 创建线程对象,调用start()方法启动线程
MyRunnable mr1 = new MyRunnable();
// MyRunnable类中没有start()方法,其父类Object类中也没有start()方法,其实现的接口Runnable中只有run()方法,没有start()方法
Thread thread1 = new Thread(mr1,"线程A");
thread1.start();
Thread thread2 = new Thread(mr1,"线程B");
thread2.start();
Thread thread3 = new Thread(mr1,"线程C");
thread3.start();
}
}
继承Thread类
1.编写简单,可直接操作线程
2.适用于单继承
实现Runnable接口
1.避免单继承局限性
2.便于共享资源

线程调度指按照特定机制为多个线程分配CPU的使用权
| 方 法 | 说 明 |
|---|---|
| void setPriority(int newPriority) | 更改线程的优先级 |
| static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
| void join() | 等待该线程终止 |
| static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
| void interrupt() | 中断线程 |
| boolean isAlive() | 测试线程是否处于活动状态 |
线程优先级由1~10表示,1最低,默认优先级为5优先级高的线程获得CPU资源的概率较大
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1= new Thread (mr,"线程A");
Thread t2 = new Thread ( mr,"线程B");
//输出两个线程的优先级
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
t1.setPriority (Thread.MAX_PRIORITY);
t2.setPriority (Thread.MIN_PRIORITY);
// 输出两个线程的优先级
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
t1.start();
t2.start();
//线程优先级高只能说明线程获取CPU资源的概率大一些,
//不能保证每一次优先级高的线程先获取CPU资源
}
让线程暂时睡眠指定时长,线程进入阻塞状态睡眠时间过后线程会再进入可运行状态
public class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
if (i == 5) {
try {
System.out.println(Thread.currentThread().getName()+"开始休眠");
//线程休眠5s
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+"休眠结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
使当前线程暂停执行,等待其他线程结束后再继续执行本线程
public final void join()
public final void join(long mills)
public final void join(long mills,int nanos)
millis:以毫秒为单位的等待时长
nanos:要等待的附加纳秒时长
需处理InterruptedException异常
public class MyRunnableTest {
public static void main(String[] args) {
Thread tr = new Thread(new MyRunnable(), "线程A");
tr.start();
for (int i = 1; i <= 10; i++) {
if (i == 3) {
try {
/*
* 线程强制执行:tr强制执行,一直等到tr执行完毕之后,
* 才会释放CPU资源给其它线程执行,在调用join()方法之前,
* 多个线程依然是抢占CPU
*/
tr.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
暂停当前线程,允许其他具有相同优先级的线程获得运行机会该线程处于就绪状态,不转为阻塞状态
public class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
if(i==3){
System.out.print("线程礼让:");
/*
* 线程礼让:让当前执行run()方法的线程释放CPU资源,
* 给其它线程一个获得CPU资源的机会,
* 但是当前线程还会抢占CPU资源,也就是说,
* 当前线程释放CPU资源后,会与其它线程再一次抢占CPU,
* 就看其它线程能不能抓住这个机会
*/
Thread.yield();
}
}
}
}
public class Site implements Runnable {
private int count = 10;
private int num = 0;
@Override
public void run() {
while (true) {
if (count <= 0) {
break;
}
//如果票的数量小于日,就不在卖票
count--;
num++;
//买票过程中模拟网速缓慢
System.out.println(Thread.currentThread().getName() + "买到了第" + num
+ "张票,还剩余" + count + "张票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Test {
public static void main(String[] args) {
Site site = new Site( );
Thread t1 = new Thread( site,"张三");
Thread t2 = new Thread( site,"李四");
Thread t3 = new Thread( site,"王五");
t1.start();
t2.start();
t3.start();
/*
* 当多个线程操作共享数据的时候容易出现问题:
* 在一个线程操作这个共享数据的时候,还没有完全操作完毕,
* 线程失去了CPU资源,CPU被另外一个线程获取,
* 另外一个线程会接着上一个线程操作的数据继续进行操作
* 当另外一个线程操作数据完毕之后,第一个线程又获取了CPU资源,
* 此时,第一个线程看到的数据是第二个线程操作后的数据,
* 由此就会引发数据不安全的问题。
*/
}
}
运行结果 张三买到了第3张票,还剩余7张票 李四买到了第3张票,还剩余7张票 王五买到了第3张票,还剩余7张票 王五买到了第6张票,还剩余4张票 张三买到了第6张票,还剩余4张票 李四买到了第6张票,还剩余4张票 李四买到了第7张票,还剩余3张票 王五买到了第7张票,还剩余3张票 张三买到了第7张票,还剩余3张票 张三买到了第8张票,还剩余2张票 李四买到了第8张票,还剩余2张票 王五买到了第8张票,还剩余2张票 张三买到了第10张票,还剩余0张票 王五买到了第10张票,还剩余0张票
同步方法
1.使用synchronized修饰的方法控制对类成员变量的访问
访问修饰符 synchronized 返回类型 方法名(参数列表){……}
或者
synchronized 访问修饰符 返回类型 方法名(参数列表){……}
public class Site implements Runnable {
private int count = 10;
private int num = 0;
@Override
public void run() {
while (true) {
if(!sale()){
break;
}
}
}
public synchronized boolean sale() {
if (count <= 0) {
return false;
}
//如果票的数量小于日,就不在卖票
count--;
num++;
//买票过程中模拟网速缓慢
System.out.println(Thread.currentThread().getName() + "买到了第" + num
+ "张票,还剩余" + count + "张票");
try {
Thread.sleep(1000);
//this.notifyAll();
//this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
}
运行结果: 张三买到了第1张票,还剩余9张票 张三买到了第2张票,还剩余8张票 张三买到了第3张票,还剩余7张票 王五买到了第4张票,还剩余6张票 王五买到了第5张票,还剩余5张票 王五买到了第6张票,还剩余4张票 王五买到了第7张票,还剩余3张票 王五买到了第8张票,还剩余2张票 王五买到了第9张票,还剩余1张票 李四买到了第10张票,还剩余0张票
2使用synchronized关键字修饰的代码块
public class Site implements Runnable {
private int count = 10;
private int num = 0;
@Override
public void run() {
while (true) {
synchronized (this) {
if (count <= 0) {
break;
}
// 如果票的数量小于日,就不在卖票
count--;
num++;
// 买票过程中模拟网速缓慢
System.out.println(Thread.currentThread().getName() + "买到了第"
+ num + "张票,还剩余" + count + "张票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
运行结果: 张三买到了第1张票,还剩余9张票 张三买到了第2张票,还剩余8张票 张三买到了第3张票,还剩余7张票 张三买到了第4张票,还剩余6张票 张三买到了第5张票,还剩余5张票 张三买到了第6张票,还剩余4张票 王五买到了第7张票,还剩余3张票 王五买到了第8张票,还剩余2张票 李四买到了第9张票,还剩余1张票 李四买到了第10张票,还剩余0张票
| ** ** | 方法是否同步 | 效率比较 | 适合场景 |
|---|---|---|---|
| 线程安全 | 是 | 低 | 多线程并发共享资源 |
| 非线程安全 | 否 | 高 | 单线程 |
Hashtable && HashMap
Hashtable
1.继承关系实现了Map接口,Hashtable继承Dictionary类
2.线程安全,效率较低
3.键和值都不允许为null
HashMap
1.继承关系实现了Map接口,继承AbstractMap类
2.非线程安全,效率较高
3.键和值都允许为null
StringBuffer && StringBuilder
前者线程安全,后者非线程安全