文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

一篇文章带你Java多线程入门

2024-04-02 19:55

关注

多线程的四种创建方式

1.继承Thread类

 
//创建一个继承于Thread类的子类
public class MThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i%2==0)
                System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
public class Threadtest {
	public static void main(String[] args) {
		//3.创建Thread类的子类的对象
		MThread t1=new MThread();
		//4.通过此对象调用start()
		t1.start();		//start方法来实现启动线程,并调用run方法,从而真正实现了多线程。同时run方法它只是一个普通的函数方法,不需要线程调用start方法也可以调用它.

		
	}
}

2.实现Runnable接口

 
class  window implements Runnable{
	private int ticket =100;
	public void run() {
		while(true) {
			if(ticket >0) {
				System.out.println(Thread.currentThread().getName()+"卖票,票号为:"+ticket);
				ticket--;
			}else
				break;
			
		}
	}
}
public class RunnableTest {
	public static void main(String[] args) {
		window w=new window();
		//三个线程用的同一个window,都执行同一个window的run,因此在设置票的数量时不需要设置为static
		Thread t1=new Thread(w);
		Thread t2=new Thread(w);
		Thread t3=new Thread(w);
		t1.setName("窗口一");
		t2.setName("窗口二");
		t3.setName("窗口三");
		t1.start();
		t2.start();
		t3.start();
		
	}
}

3.实现Callable接口



//1.创建一个实现Callable的实现类
class NumThread implements Callable{
	//2.实现call方法,将此线程需要执行的操作声明在call()方法中
	public Object call() throws Exception{
		int sum=0;
		for(int i=0;i<=100;i++) {
			if(i%2==0) {
				System.out.println(i);
				sum+=i;
			}
		}
		return sum;
	}
}
public class CallableWay {
	public static void main(String[] args) {
		//3.创建Callable接口实现类的对象
		NumThread numThread =new NumThread();
		//4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask对象
		FutureTask futureTask =new FutureTask(numThread);
		//5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()方法
		new Thread(futureTask).start();
		try {
			//6.获取Callable中call()的返回值
			//get()返回值即为FutureTask构造参数Callable实现类重写的call()的返回值
			Object sum = futureTask.get();
			System.out.println("总和为:"+sum);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
}

4.使用线程池


class NumberThread implements Runnable{
		public void run() {	
			for(int i=0;i<=100;i++) {
				if(i%2==0) {
					System.out.println(Thread.currentThread().getName()+":"+i);
				}
			}
		}
}
public class Thread4 {
	public static void main(String[] args) {
		//1.提供指定线程数量的线程池
		ExecutorService service =Executors.newScheduledThreadPool(10);
		//2.执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
		service.execute(new NumberThread()); //适用于Runnable
		//service.submit(); //适用于Callable
		//3.关闭线程池
		service.shutdown();
	}

}

线程的优先级

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5 —>默认优先级

如何获取和设置当前线程优先级:

getpriority()		//获取线程的优先级
setpriority(int p)		//设置线程的优先级

说明:高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上来讲,高优先级的线程高概率的情况下被执行,并不意味着只有高优先级的线程执行完后,低优先级的线程才执行。

测试Thread中常用的方法

1.star():启动当前线程;调用当前线程的run()
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字
6.yield():释放当前线程cpu的执行权,各个线程重新“竞争”7.join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完之后,线程a才结束阻塞状态
8.stop():已过时。当执行此方法时,强制结束当前线程
9.sleep(long millitime):让当前线程“睡眠”指定millitime毫秒。在指定的时间内,当前线程是处于阻塞状态
10.isAlive():判断当前线程是否存活

线程的生命周期

在这里插入图片描述

多线程的同步控制

1.同步代码块


synchronized(同步监视器){
 	// 需要被同步的代码
 }

下面展示实现Runnable接口的情况。

class TicketWindow implements Runnable {
    private int ticket = 100;
    private Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (obj) {		
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + " 卖出第 " + ticket + " 张票");
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

public class ThreadSync {
    public static void main(String[] args) {
        TicketWindow ticketWindow = new TicketWindow();

        Thread thread1 = new Thread(ticketWindow);
        Thread thread2 = new Thread(ticketWindow);
        Thread thread3 = new Thread(ticketWindow);

        thread1.setName("售票窗口1");
        thread2.setName("售票窗口2");
        thread3.setName("售票窗口3");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

下面展示继承Thread类的情况。

class TicketWindow1 extends Thread {    private static int ticket = 100;    private static Object obj = new Object();    @Override    public void run() {        while (true) {            synchronized (obj) {                if (ticket > 0) {                    try {                        Thread.sleep(100);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println(Thread.currentThread().getName() + " 卖出第 " + ticket + " 张票");                    ticket--;                } else {                    break;                }            }        }    }}public class ThreadSync1 {    public static void main(String[] args) {        Thread thread1 = new TicketWindow1();        Thread thread2 = new TicketWindow1();        Thread thread3 = new TicketWindow1();        thread1.setName("售票窗口1");        thread2.setName("售票窗口2");        thread3.setName("售票窗口3");        thread1.start();        thread2.start();        thread3.start();    }}class TicketWindow1 extends Thread {
    private static int ticket = 100;
    private static Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (obj) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + " 卖出第 " + ticket + " 张票");
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

public class ThreadSync1 {
    public static void main(String[] args) {
        Thread thread1 = new TicketWindow1();
        Thread thread2 = new TicketWindow1();
        Thread thread3 = new TicketWindow1();

        thread1.setName("售票窗口1");
        thread2.setName("售票窗口2");
        thread3.setName("售票窗口3");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

对比二者不同二者不同在于synchronized(同步监视器)中的同步监视器,

实现Runnable接口的情况下,同步监视器不需要用static,因为Runnable接口的实现类只被创建一次,三个线程的同步监视器是同一个。而继承Thread类的情况下,同步监视器如不声明为static则被声明了三次,三个线程的同步监视器不是同一。

2.同步方法


访问修饰符 synchronized 返回值 方法名(参数列表) {
	// 同步代码块
}

下面展示实现Runnable接口的情况。

class TicketWindow implements Runnable {
    private int ticket = 100;

    @Override
    public void run() {
        while (ticket > 0) {
            sellTicket();
        }
    }

    public synchronized void sellTicket() {
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + " 卖出第 " + ticket + " 张票");
            ticket--;
        }
    }
}

下面展示继承Thread类的情况。

class TicketWindow1 extends Thread {
    private static int ticket = 100;

    @Override
    public void run() {
        while (ticket > 0) {
            sellTicket();
        }
    }

    
    public static synchronized void sellTicket() {
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + " 卖出第 " + ticket + " 张票");
            ticket--;
        }
    }
}

3.同步锁

// 1 获得一个锁
Lock lock = new ReentrantLock();

// 2 加锁
lock.lock();
// 同步代码块

// 3 解锁
lock.unlock();

下面展示代码实现。

class TicketWindowLock implements Runnable {
    private int ticket = 100;
    // 1 获得一个锁
    private Lock lock = new ReentrantLock();
    

    @Override
    public void run() {
        while (true) {

            try {
                // 2 上锁
                lock.lock();

                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + " 卖出第 " + ticket + " 张票");
                    ticket--;
                } else {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 3 解锁。使用 try catch finally,将解锁操作放在finally语句块中,保证锁一定会被释放
                lock.unlock();
            }
        }
    }
}

synchronized与lock锁有何异同

线程通信

wait/notify模式

涉及到的三个方法

1.wait():一旦执行此方法,当前线程就会进入阻塞状态,并且释放同步监视器。

2.notify():一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,就优先唤醒高优先级的线程

3.notifyAll():一旦执行此方法,所有的线程都会被唤醒

说明上述三个方法都必须使用在同步代码块或同步方法中的同步监视器中,否则会出现异常

上述三个方法都是定义在Object类中的。

sleep和wait的异同

相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。

不同点:

1)俩个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()

2)调用的要求不同:sleep可以在任何场景下调用,而wait只能在同步代码块或者同步方法的同步监视器中

3)关于是否释放同步监视器:如果俩个方法都使用在同步代码块或同步方法中,sleep()不释放,而wait()释放。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯