多线程

    技术2022-07-20  66

    多线程的实现

    在Java中要想实现多线程的程序,必须依靠一个线程的主体类,即主线程(执行主方法(main)的线程)。然后此类继承Thread类或实现Runnable接口。

    1. 继承Thread类

    java.lang.Thread是操作线程的类,任何类只需要继承Thread类就可以成为一个线程的主类。 Thread类下的两个重要方法: run()和start()方法。 线程执行体:run()。(线程需要完成的任务) 线程的起点:start()。(线程的启动,启动后执行的方法体是run()方法定义的代码) 程序的起点:main()。

    实例:

    //1.创建一个Thread类的子类 public class MyThread extends Thread{ //2.重写Thread类中的run方法,设置线程任务 @Override public void run(){ for (int i = 0; i < 20; i++) { System.out.println("run:"+i); } } } public class doMain { public static void main(String[] args) { //3.创建Thread类的子类对象 MyThread mt = new MyThread(); //4.调用Thread类中的start(),开启新的线程,执行run() mt.start(); for (int i = 0; i < 20; i++) { System.out.println("main:"+i); } } }

    Thread类的常用方法: getName() :取得线程名字 setName() :设置线程名字 currentThread() :取得线程名字 sleep(long millitime) :使当前正在执行的程序以指定的毫秒数暂定

    2.实现Runnable接口:

    为了避免单继承局限的问题,我们可以使用Runnable接口来实现多线程。 要启动多线程,就一定需要通过Thread类中的start()方法,但是Runnable接口中没有提供可以被继承的start()方法。这时就需要借住Thread类中提供的有参构造方法:

    public Thread(Runnable target)此方法可以接收一个Runnable接口对象

    实例:

    public static void main(String[] args) { // TODO Auto-generated method stub MyThread2 m=new MyThread2(); new Thread(m).start(); new Thread(m).start(); } class MyThread2 implements Runnable{ private int ticket = 5; public void run(){ while(true){ System.out.println("Runnable ticket = " + ticket--); if(ticket < 0){ break; } } } }

    3.线程优先级设置

    通过 线程名.setPriority()的方法设置,线程优先级的范围是:1-10,默认为5

    package cn.itcast_04; /* * 我们的线程没有设置优先级,肯定有默认优先级。 * 那么,默认优先级是多少呢? * 如何获取线程对象的优先级? * public final int getPriority():返回线程对象的优先级 * 如何设置线程对象的优先级呢? * public final void setPriority(int newPriority):更改线程的优先级。 * * 注意: * 线程默认优先级是5。 * 线程优先级的范围是:1-10。 * 线程优先级高仅仅表示线程获取的 CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。 * * IllegalArgumentException:非法参数异常。 * 抛出的异常表明向方法传递了一个不合法或不正确的参数。 * */ public class ThreadPriority extends Thread { @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(getName() + ":" + x); } } public class ThreadPriorityDemo { public static void main(String[] args) { ThreadPriority tp1 = new ThreadPriority(); ThreadPriority tp2 = new ThreadPriority(); ThreadPriority tp3 = new ThreadPriority(); tp1.setName("东方不败"); tp2.setName("岳不群"); tp3.setName("林平之"); // 获取默认优先级 //System.out.println(tp1.getPriority()); //5 //System.out.println(tp2.getPriority()); //5 //System.out.println(tp3.getPriority()); //5 // 设置线程优先级 // tp1.setPriority(100000);//IllegalArgumentException:非法参数异常。 // 设置正确的线程优先级 tp1.setPriority(10); tp2.setPriority(1); tp1.start(); tp2.start(); tp3.start(); } }

    4.线程安全问题

    线程安全出现的根本原因:

    存在两个或者两个以上的线程对象共享同一个资源;多线程操作共享资源代码有多个语句。

    解决方法:通过同步操作来解决。 同步操作:一个代码块中的多个操作在同一时间段内只能由一个线程进行,其他线程要等待此线程完成后才可以继续执行。 三种方法实现同步操作:

    同步代码块: synchronized(this){ //需要被同步操作的代码 } 应用实例: 实现卖票程序 public class RunnableImpl implements Runnable{ //定义一个多线程共享的票源 private int ticket = 100; //设置线程任务:卖票 @Override public void run() { while(true){ //先判断票是否存在 synchronized (this){ if (ticket>0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //票存在,卖票 System.out.println(Thread.currentThread().getName() + "->>正在卖第" + ticket + "张票"); ticket--; }else { break; } } } } } 同步函数: 利用synchronized定义的函数。 同步函数就是使用synchronized修饰一个函数 //实现卖票程序 public class RunnableImpl implements Runnable{ //定义一个多线程共享的票源 private int ticket = 100; //设置线程任务:卖票 @Override public void run() { while(true){ sale(); } } public synchronized void sale(){ //先判断票是否存在 synchronized (this){ if (ticket>0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //票存在,卖票 System.out.println(Thread.currentThread().getName() + "->>正在卖第" + ticket + "张票"); ticket--; } } } } Lock锁: 三步走。1.创建ReentrantLock对象 2.获取锁 3.释放锁 //实现卖票程序 public class RunnableImpl implements Runnable{ //定义一个多线程共享的票源 private int ticket = 100; //1.创建ReentrantLock对象 Lock lk = new ReentrantLock(); //设置线程任务:卖票 @Override public void run() { while(true){ //2.在可能出现线程安全的代码前调用Lock接口中的Lock方法获取锁. lk.lock(); if (ticket>0) { try { Thread.sleep(10); //票存在,卖票 System.out.println(Thread.currentThread().getName() + "->>正在卖第" + ticket + "张票"); ticket--; } catch (InterruptedException e) { e.printStackTrace(); }finally { //3.在可能出现线程安全的代码后释放锁。 lk.unlock(); } } } } }

    5. 并发学习-吃包子案例

    package com.leyou.item.controller; public class Demo01WaitAndNotify { public static void main(String[] args) { //创建一个锁对象 Object o = new Object(); //创建一个顾客线程(消费者) new Thread(){ @Override public void run() { //保证等待和唤醒的线程只有一个执行,需要使用同步技术 synchronized (o){ System.out.println("告知老板要的包子的种类和数量"); //调用wait方法,放弃cpu的执行,进入到waiting状态(无限等待) try { //wait()不能走throws 因为父类的run()没有抛异常,所以子类也不能抛异常 //而只能用try catch o.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("包子已做好,开吃"); } } }.start(); //创建一个老板线程 new Thread(){ @Override public void run() { //花5秒做包子,也不能使用throws方法 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o){ System.out.println("老板5秒之后做好包子,告知顾客,可以吃包子了"); //唤醒顾客 o.notify(); } } }.start(); } }
    Processed: 0.009, SQL: 9