Java基础之多线程详解
Java多线程是抢占式,谁的优先级高,谁就先执行。
Java使用 java.lang.Thread 类代表线程,所有的线程对象都必须是Thread类或其子类的实例。
Thread类
构造方法:
public Thread() :分配一个新的线程对象。
public Thread(String name) :分配一个指定名字的新的线程对象。
public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。
常用方法:
public String getName() :获取当前线程名称。
public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
public void run() :此线程要执行的任务在此处定义代码。
public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
public void Join() 终止该线程
创建并启动多线程的步骤
一、使用基类Thread
1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把 run()方法称为线程执行体。
2. 创建Thread子类的实例,即创建了线程对象
3. 调用线程对象的start()方法来启动该线程
-
public class MyThread extends Thread{
-
@Override
-
public void run() {
-
for( int i = 0;i < 20;i++){
-
System.out.println("run"+i);
-
}
-
}
-
}
-
public static void main (String[]args){
-
//多线程
-
MyThread my1 = new MyThread();
-
//my1.run();调用run()方法 单线程
-
my1.start();//执行run()方法 多线程 新开一个栈空间
-
//main执行
-
for(int i = 0;i < 20;i++){
-
System.out.println("main"+i);
-
}
-
}
二、使用Runnable接口
1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
3. 调用线程对象的start()方法来启动线程
-
public class DemoRunnableImpl implements Runnable{//步骤一
-
@Override
-
public void run(){
-
for(int i = 0;i < 5;i++){
-
System.out.println(Thread.currentThread().getName()+"-->"+i);
-
}
-
}
-
}
-
public static void main (String[] args){
-
DemoRunnableImpl demo =new DemoRunnableImpl();//步骤二
-
Thread thread= new Thread (demo);
-
thread.start();//步骤三
-
}
三、使用匿名内部类
-
public static void main(String[] args){
-
//线程的父类是Thread
-
new Thread(){
-
@Override
-
public void run(){
-
for(int i = 0;i < 5;i++){
-
System.out.println(Thread.currentThread().getName()+"小小张自由");
-
}
-
}
-
}.start();
-
//线程的接口是Runnable
-
Runnable r = new Runnable(){
-
@Override
-
public void run(){
-
for(int i = 0;i < 5;i++){
-
System.out.println(Thread.currentThread().getName()+"身体健康");
-
}
-
}
-
};
-
new Thread(r).start();
-
}
解决线程安全问题
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无操作,一般来说,这个全局变量是线程安全的。
若有多个线程同时执行写操作,一般都需要考虑线程同步, 否则的话就可能影响线程安全。
synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
锁对象 可以是任意类型。多个线程对象,要使用同一把锁。在任何时候,最多运行一个线程拥有同步锁,谁拿到锁就进入代码块,其他线程只能等待。
一、同步代码块
-
//语法格式
-
synchronized(同步锁){
-
//需要同步操作的代码
-
}
-
//示例
-
private int cont = 100;
-
Object obj = new Object();
-
@Override
-
public void run(){
-
synchronized(obj){ //被锁住的代码
-
while(cont>0){
-
//线程休眠10毫秒
-
try{
-
Thread.sleep(10);
-
}catch(Exceptione){
-
System.out.println(e.getMessage());
-
}
-
System.out.println(Thread.currentThread().getName()+"正在抢第"+cont+"票");
-
cont--;
-
}
-
}
-
}
二、同步方法
将需要同步操作的代码,抽出来。放到一个方法中。Run()方法再调用同步方法
-
public synchronized void method(){
-
//可能会产生线程安全问题的代码
-
}
三、锁(Lock)机制
1.在成员位置创建一个ReentrantLock对象
2.在可能出现安全问题的代码前调用Lock接口中的方法Lock获取锁
3.在可能出现安全问题的代码后调用Lock接口中的方法unLock释放锁
-
public class DemoRunnableImpl implements Runnable {
-
private int cont = 100;
-
Lock lock=new ReentrantLock();//创建一个ReentrantLock对象
-
@Override
-
public void run() {
-
lock.lock();//获取锁
-
while (cont > 0) {
-
//线程休眠10毫秒
-
try {
-
Thread.sleep(10);
-
} catch (Exception e) {
-
System.out.println(e.getMessage());
-
}
-
System.out.println(Thread.currentThread().getName() + "正在抢第" + cont + "票");
-
cont--;
-
}
-
lock.unlock();//释放锁
-
}
-
}
线程之间的通信
多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据。
线程状态概述
等待和唤醒案例——生产者和消费者
1.顾客和老板线程必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行
2.同步使用的锁对象必须保证唯一
3.只有锁对象才能能用wait()和notify()方法
-
public static void main(String[] args) {
-
Object obj=new Object();//锁对象
-
//消费者
-
new Thread(){
-
@Override
-
public void run() {
-
while (true){
-
synchronized (obj){ //同步代码段
-
System.out.println("告知老板要的包子种类和数量");
-
try {
-
obj.wait();//线程等待
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
//唤醒之后执行的代码
-
System.out.println("包子已经做好了,开吃!");
-
}
-
}
-
}
-
}.start();
-
//生产者
-
new Thread(){
-
@Override
-
public void run() {
-
while (true){
-
try {
-
Thread.sleep(5000); //花5s做包子
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
synchronized (obj){ //同步代码段
-
System.out.println("老板5秒钟包子做好了,可以吃包子了!");
-
//做好包子,调用notify方法,唤醒顾客吃包子
-
obj.notify();
-
System.out.println("---------------------");
-
}
-
}
-
}
-
}.start();
-
}
创作不易,如果本篇博客对您有一定的帮助,大家记得留言+点赞哦。
文章来源: blog.csdn.net,作者:小小张自由—>张有博,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/promsing/article/details/112408018
- 点赞
- 收藏
- 关注作者
评论(0)