目录
多线程
什么是多线程:如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为“多线程”多个线程交替占用CPU资源,而非真正的并行执行
多线程好处:1、充分利用CPU的资源,2、简化编程模型,3、带来良好的用户体验
Thread类:Java提供了java.lang.Thread类支持多线程编程
主线程
main()方法即为主线程入口
产生其他子线程的线程
必须最后完成执行,因为它执行各种关闭动作
public static void main(String args[]) {
Thread t= Thread.currentThread();
System.out.println("当前线程是: "+t.getName());
t.setName("MyJavaThread");
System.out.println("当前线程名是: "+t.getName());
}
线程的创建和启动
在Java中创建线程的两种方式
继承java.lang.Thread类
实现java.lang.Runnable接口
使用线程的步骤:1、定义线程2、创建线程对象3、启动线程4、终止线程
1、继承Thread类创建线程
定义MyThread类继承Thread类
重写run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
实例:
public class MyThread extends Thread{
//重写run()方法
public void run(){
for(int i=1;i<100;i++){ System.out.println(
Thread.currentThread().getName()+":"+i);
}
}
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); //启动线程
}
多个线程交替执行,不是真正的“并行” 线程每次执行时长由分配的CPU时间片长度决定
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start();
t2.start();
启动线程不可以直接调用run()方法,要使用start()方法
2、实现Runnable接口创建线程
定义MyRunnable类实现Runnable接口
实现run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
public class MyRunnable implements Runnable{
public void run(){
for(int i=1;i<100;i++){ System.out.println(
Thread.currentThread().getName()+":"+i);
}
}
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread myThread = new Thread(myRunnable);
thread.start(); //启动线程
}
继承Thread类: 1、编写简单,可直接操作线程;2、适用于单继承
实现Runnable接口:1、避免单继承局限性;2、便于共享资源
线程状态
1、创建状态;2、就绪状态;3、运行状态;4、阻塞状态;5、死亡状态
线程调度:线程调度指按照特定机制为多个线程分配CPU的使用权
方法 | 说明 |
void setPriority(int newPriority) |
更改线程的优先级 |
static void sleep(long millis) |
在指定的毫秒数内让当前正在执行的线程休眠 |
void join() |
等待该线程终止 |
static void yield() |
暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt() |
中断线程 |
boolean isAlive() |
测试线程是否处于活动状态 |
1、线程优先级
线程优先级由1~10表示,1最低,默认优先级为5
优先级高的线程获得CPU资源的概率较大
实例:
public class Runable implements Runnable{
//重写run方法
@Override
public void run() {
for (int i = 1; i < 10; i++) {
Thread thread = Thread.currentThread();
System.out.println("你好:来自线程:" + thread.getName());
}
}
public static void main(String[] args) {
Runable runable = new Runable();
Thread thread1 = new Thread(runable);
Thread thread2 = new Thread(runable);
//修改线程名字
thread1.setName("A");
thread2.setName("B");
//设置线程优先级
thread1.setPriority(8);
thread2.setPriority(4);
//启动线程
thread1.start();
thread2.start();
}
}
2、线程休眠
让线程暂时睡眠指定时长,线程进入阻塞状态,睡眠时间过后线程会再进入可运行状态
实例:
public class Runable implements Runnable{
//重写run方法
@Override
public void run() {
for (int i = 1; i < 10; i++) {
try {
//线程休眠,并处理异常
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread = Thread.currentThread();
System.out.println("你好:来自线程:" + thread.getName());
}
}
public static void main(String[] args) {
Runable runable = new Runable();
Thread thread1 = new Thread(runable);
Thread thread2 = new Thread(runable);
//修改线程名字
thread1.setName("A");
thread2.setName("B");
//设置线程优先级
thread1.setPriority(8);
thread2.setPriority(4);
//启动线程
thread1.start();
thread2.start();
}
}
3、线程的强制运行
使当前线程暂停执行,等待其他线程结束后再继续执行本线程
方法:
1、public final void join()
2、public final void join(long mills)
3、public final void join(long mills,int nanos)
millis:以毫秒为单位的等待时长,nanos:要等待的附加纳秒时长,需处理InterruptedException异常
实例:
重写run方法
public class MyRunnable implements Runnable{
private String name;
private String gender;
public MyRunnable(String name, String gender) {
this.name = name;
this.gender = gender;
}
public MyRunnable() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public void run() {
for(int i = 0; i < 5; i++){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
}
}
实现线程阻塞:
public class JoinThreadTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable("张三","男");
Thread myThread = new Thread(myRunnable);
myThread.start();
for (int i=0;i<20;i++){
if(i==5){
try {
//线程阻塞
myThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"运行:"+i);
}
}
}
4、线程的礼让
暂停当前线程,允许其他具有相同优先级的线程获得运行机会
该线程处于就绪状态,不转为阻塞状态
方法:
public static void yield()
只是提供一种可能,但是不能保证一定会实现礼让
实例:
重写run方法
public class YieldRunnable implements Runnable{
@Override
public void run() {
for(int i=0;i<15;i++){
String name = Thread.currentThread().getName();
System.out.println(name+"正在运行:"+i);
/*if(i==3){
System.out.print(name + "线程礼让:");
Thread.yield();
}*/
System.out.print(name + "线程礼让:");
Thread.yield();
}
}
}
实现线程礼让:
public class YieldThreadTest {
public static void main(String[] args) {
YieldRunnable runnable = new YieldRunnable();
Thread t1 = new Thread(runnable);
t1.setName("线程A");
Thread t2 = new Thread(runnable);
t2.setName("线程B");
t1.start();
t2.start();
}
}
多线程共享数据引发的问题
多个线程操作同一共享资源时,将引发数据不安全问题
使用同步方法和同步代码块可以解决这些问题
使用synchronized修饰的方法控制对类成员变量的访问
同步方法语法:
访问修饰符 synchronized 返回类型 方法名(参数列表){……}
或者
synchronized 访问修饰符 返回类型 方法名(参数列表){……}
同步方法实例:
同步方法多个线程抢火车票
public class TrainRunnable implements Runnable{
private int num;
private int count = 10;
private boolean flag = false;
@Override
public void run() {
while (!flag) {
//省略代码:判断是否余票
sale();
}
System.out.println("票已抢完!");
}
private synchronized void sale(){
if (count <= 0) {
flag = true;
return;
}
try {
Thread.sleep(500); //模拟网络延时
} catch (InterruptedException e) {//…}
e.printStackTrace();
}
count--;
num++;
System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票!");
}
public static void main(String[] args) {
TrainRunnable trainTest1 = new TrainRunnable();
Thread a = new Thread(trainTest1);
Thread b = new Thread(trainTest1);
Thread c = new Thread(trainTest1);
a.setName("客户:A");
b.setName("客户:B");
c.setName("客户:C");
a.start();
b.start();
c.start();
}
}
同步代码块
使用synchronized关键字修饰的代码块
同步代码块语法:
synchronized(syncObject){
//需要同步的代码
}
syncObject为需同步的对象,通常为this,效果与同步方法相同
同步代码块多个线程抢火车票:
public class TrainThread implements Runnable{
private int num;
private int count = 10;
@Override
public void run() {
while (true) {
//省略代码:判断是否余票
synchronized (this){
if (count <= 0) {
System.out.println("票已抢完!");
break;
}
try {
Thread.sleep(500); //模拟网络延时
} catch (InterruptedException e) {//…}
e.printStackTrace();
}
count--;
num++;
System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票!");
}
}
}
public static void main(String[] args) {
TrainThread trainTest1 = new TrainThread();
Thread a = new Thread(trainTest1);
Thread b = new Thread(trainTest1);
Thread c = new Thread(trainTest1);
a.setPriority(Thread.MAX_PRIORITY);
a.setName("客户:A");
b.setName("客户:B");
c.setName("客户:C");
a.start();
b.start();
c.start();
}
}
多个并发线程访问同一资源的同步代码块时
同一时刻只能有一个线程进入synchronized(this)同步代码块
当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定
当一个线程访问一个synchronized(this)同步代码块时,其他线程可以访问该资源的非synchronized(this)同步代码
线程安全的类型
方法是否同步 | 效率 | 适合场景 | |
线程安全 | 是 | 低 | 多线程并发共享资源 |
非线程安全 | 否 | 高 | 单线程 |
为达到安全性和效率的平衡,可以根据实际场景来选择合适的类型
Hashtable 与 HashMap的区别
Hashtable:继承关系
1、实现了Map接口,Hashtable继承Dictionary类
2、线程安全,效率较低
3、键和值都不允许为null
HashMap:继承关系
1、实现了Map接口,继承AbstractMap类
2、非线程安全,效率较高
3、键和值都允许为null
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/93373.html