您当前的位置: 首页 > 

梁云亮

暂无认证

  • 1浏览

    0关注

    1211博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

第十二章 多线程编程

梁云亮 发布时间:2022-03-08 09:42:37 ,浏览量:1

12.1 多线程相关的概念

什么是程序?一个程序可以有多个进程

程序是一段静态的代码,它是应用程序执行的蓝本。

什么是进程?一个进程可以有多线程

进程是指一种正在运行的程序,有自己的地址空间。

作为蓝本的程序可以被多次加载到系统的不同内存区域分别执行,形成不同的进程。

基于进程的特点是允许计算机同时运行两个或更多的程序。

什么是线程?

线程是进程内部单一的一个顺序控制流。 一个进程在执行过程中,可以产生多个线程。每个线程也有自己产生、存在和消亡的过程。

并发当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。
并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。
区别:并发和并行是即相似又有区别的两个概念,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。在多道程序环境下,并发性是指在一段时间内宏观上有多个程序在同时运行,但在单处理机系统中,每一时刻却仅能有一道程序执行,故微观上这些程序只能是分时地交替执行。倘若在计算机系统中有多个处理机,则这些可以并发执行的程序便可被分配到多个处理机上,实现并行执行,即利用每个处理机来处理一个可并发执行的程序,这样,多个程序便可以同时执行。 

image-20210128141457317

12.2 实现多线程类方法 12.2.1 Runnable接口
/*
 * Copyright 2006-2021 webrx Group.
 */
package cn.webrx;

/**
 * 

*

 * 
* * @author webrx [webrx@126.com] * @version 1.0 * @date 2021-01-28 14:24:09 */ public class Thread2 implements Runnable{ public void run() { System.out.println("Thread2...."); } }
12.2.2 继承Thread类
/*
 * Copyright 2006-2021 webrx Group.
 */
package cn.webrx;

/**
 * 

*

 * 
* * @author webrx [webrx@126.com] * @version 1.0 * @date 2021-01-28 14:27:03 */ public class Thread3 extends Thread{ public void run() { System.out.println("Thread3"); } }
12.2.3 综合线程实现
/*
 * Copyright 2006-2021 webrx Group.
 */
package cn.webrx;

/**
 * 

*

 * 
* * @author webrx [webrx@126.com] * @version 1.0 * @date 2021-01-28 14:19:03 */ public class Thread1 { public static void main(String[] args) { System.out.println("hello world main thread"); //建立方法一 实现Runnable接口,并作为Thread类参数 new Thread(() -> { System.out.println("Thread1"); }).start(); Thread t2 = new Thread(new Thread2()); t2.start(); //建立方法二 继承Thread 类,重写run方法 var t3 = new Thread3(); t3.setName("线程三"); t3.start(); } }
12.3 多线程状态及常用方法

image-20210128150722176

image-20210128150737763

/*
 * Copyright 2006-2021 webrx Group.
 */
package cn.webrx;

import java.util.concurrent.TimeUnit;

/**
 * 

*

 * 
* * @author webrx [webrx@126.com] * @version 1.0 * @date 2021-01-28 14:27:03 */ public class Thread4 { public static void main(String[] args) { Thread t0 = new Thread(()->{ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); System.out.println(Thread.currentThread().getPriority()); },"ttt1"); t0.setName("ttt-000"); t0.setPriority(10); t0.start(); //设置线程 Thread.currentThread().setName("主线程"); //设置优先级 1 - 10 Thread.currentThread().setPriority(Thread.MIN_PRIORITY); try { //Thread.sleep(10000); TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread().getName()); System.out.println(Thread.currentThread().getPriority()); } catch (InterruptedException e) { e.printStackTrace(); } } }
12.3.1 多线程实现UDP聊天
/*
 * Copyright 2006-2021 webrx Group.
 */
package cn.chat;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

/**
 * 

*

 * 
* * @author webrx [webrx@126.com] * @version 1.0 * @date 2021-01-28 15:35:49 */ public class One { public static Set set = new HashSet(); public static void main(String[] args) { String name = args[2]; String ip = args[0]; int port = Integer.parseInt(args[1]); //接收 new Thread(() -> { try { DatagramSocket ds = new DatagramSocket(port); DatagramPacket dp = new DatagramPacket(new byte[1024], 1024); while (true) { ds.receive(dp); String nip = dp.getAddress().getHostAddress(); set.add(nip); System.out.println(nip+new String(dp.getData(), 0, dp.getLength(), "utf-8")); } } catch (Exception e) { e.printStackTrace(); } }).start(); //发线程 广播 new Thread(() -> { Scanner sc = new Scanner(System.in); try { DatagramSocket ds = new DatagramSocket(); while (true) { String msg = String.format("%s:%s [%3$tF %3$tT] - [ %4$d ]%n", name, sc.nextLine(), System.currentTimeMillis(),set.size()); byte[] data = msg.getBytes(StandardCharsets.UTF_8); int len = data.length; for (int i = 1; i System.out.println("hello")); t.setName("t1"); t.setPriority(10); t.start(); My my = new My(); my.start(); Thread t3 = new Thread(new User()); t3.start(); Thread t4 = new Thread(){ public void run() { System.out.println("t444444444444444"); } }; t4.start(); } } class User implements Runnable{ public void run() { System.out.println("useruseruser"); } } class My extends Thread{ public void run() { System.out.println("hello2222"); } }
12.4 java多线程实现 12.4.1 多线程模拟售票
/*
 * Copyright 2006-2021 webrx Group.
 */
package cn.exam;

import java.util.concurrent.TimeUnit;

/**
 * 

*

 * 
* * @author webrx [webrx@126.com] * @version 1.0 * @date 2021-01-29 10:35:33 */ public class SellTicket { public static void main(String[] args) { Ticket t = new Ticket(50); Thread t1 = new Thread(t,"科学大道"); Thread t2 = new Thread(t,"东风路"); Thread t3 = new Thread(t,"火车站"); Thread t4 = new Thread(t,"瑞达路"); t1.start();t2.start();t3.start();t4.start(); } } class Ticket implements Runnable { private int num = 100; public Ticket() { } public Ticket(int num) { this.num = num; } public void run() { while(true){ synchronized (this) { if (num > 0) { System.out.printf("[%s] 售出一张票,剩余%d张票%n", Thread.currentThread().getName(), --num); } else { System.out.printf("%n[%s] 票已售完,停止售票。", Thread.currentThread().getName()); break; } } try{ TimeUnit.SECONDS.sleep(1); }catch(Exception e){ e.printStackTrace(); } } } }
12.4.2 定时关机
/*
 * Copyright (c) 2006, 2021, webrx.cn All rights reserved.
 *
 */
package cn.exam;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 

Project: part12 - MyClose *

Powered By webrx *

Created By IntelliJ IDEA On 2021-01-29 14:49:42 *

Description : * * @author webrx [webrx@126.com] * @version 1.0 * @since 15 */ public class MyClose { public static void main(String[] args) { //多长时间后关机 5m new Thread(()->{ long t1 = System.currentTimeMillis(); while(true){ long ok = System.currentTimeMillis() - t1; if(ok >= 5 * 1000) break; } System.out.println("系统正在关机5..."); }).start(); // new Thread(()->{ try{ TimeUnit.SECONDS.sleep(10); }catch(Exception e){ e.printStackTrace(); } System.out.println("系统正在关机10"); }).start(); //指定时间关机 2021-1-30 21:30:00 new Thread(()->{ String s = "2021-1-29 15:13:59"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); long end = 0; try { end = sdf.parse(s).getTime(); } catch (ParseException e) { e.printStackTrace(); } try{ TimeUnit.MILLISECONDS.sleep(end-System.currentTimeMillis()); }catch(Exception e){ e.printStackTrace(); } System.out.printf("%s - 系统正在关机%n",s); }).start(); } }

12.5 多线程工具类 12.5.1 Timer TimerTask
/*
 * Copyright (c) 2006, 2021, webrx.cn All rights reserved.
 *
 */
package cn.exam;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 

Project: part12 - TimerTest *

Powered By webrx *

Created By IntelliJ IDEA On 2021-01-29 15:18:10 *

Description : * * @author webrx [webrx@126.com] * @version 1.0 * @since 15 */ public class TimerTest { public static void main(String[] args) throws ParseException { Timer t = new Timer(); t.schedule(new TimerTask() { public void run() { System.out.printf("%1$tF %1$tT%n",System.currentTimeMillis()); //t.cancel(); } }, 5000,1000); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); t.schedule(new TimerTask() { public void run() { t.cancel(); } },sdf.parse("2021-01-29 15:28:30")); Timer t2 = new Timer(); TimerTask tt = new TimerTask() { public void run() { System.out.println("hello world Timer"); t2.cancel(); } }; t2.schedule(tt,10000); } }

12.5.2 TimeUnit

image-20210129153450192

12.5.3 CountDownLatch

java.util.concurrent.CountDownLatch

  • 实现方法一 一个线程实现功能,一个线程统计

    /*
     * Copyright (c) 2006, 2021, webrx.cn All rights reserved.
     *
     */
    package cn.webrx;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 

    Project: part12 - Sync1 *

    Powered By webrx *

    Created By IntelliJ IDEA On 2021-01-29 16:36:55 *

    Description : * * @author webrx [webrx@126.com] * @version 1.0 * @since 15 */ public class Sync2 { public static void main(String[] args) { MySync2 ms = new MySync2(); new Thread(() -> { for (int i = 1; i { System.out.println("t2"); while (!ms.count()) ; System.out.println("已经有五个了"); }, "t2").start(); } } class MySync2 { private volatile List list = new ArrayList(); public void add() { list.add("add" + list.size()); System.out.println(String.format("%d = %s", list.size(), list.get(list.size() - 1))); } public boolean count() { boolean f = false; if (list.size() >= 5) { System.out.println(Thread.currentThread().getName() + "线程启动"); f = true; } return f; } }

    案例二

    /*
     * Copyright (c) 2006, 2021, webrx.cn All rights reserved.
     *
     */
    package cn.webrx;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次
     * //参数count为计数值
     * public CountDownLatch(int count) {  };
     * 调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
     * public void await() throws InterruptedException { };
     * 和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
     * public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
     * 将count值减1 public void countDown() { };
     * CountDownLatch CyclicBarrier、Semaphore、concurrentHashMap和BlockingQueue
     * 

    Project: untitled - Demo *

    Powered by webrx On 2021-01-31 18:56:45 *

    Created by IntelliJ IDEA * * @author webrx [webrx@126.com] * @version 1.0 * @since 15 */ public class Test{ static void m(){ for(int i=0;i{ System.out.println("收尾开始"); try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } //latch.countDown(); System.out.println("真正程序的大结局"); },"END").start(); new Thread(Test::m,"t1").start(); new Thread(Test::m,"t2").start(); new Thread(Test::m,"t3").start(); new Thread(Test::m,"t4").start(); m(); System.out.println("main - 大结局"); } }

    实现多个线程,有一个线程收尾工作
    /*
     * Copyright (c) 2006, 2021, webrx.cn All rights reserved.
     */
    package cn.thread;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.TimeUnit;
    /**
     * 

    Project: part12 - T8 *

    Powered By webrx *

    Created By IntelliJ IDEA On 2021-02-01 10:46:15 *

    Description : 实现多个线程,有一个线程收尾工作。 * * @author webrx [webrx@126.com] * @version 1.0 * @since 15 */ public class T8 { static CountDownLatch latch = new CountDownLatch(5); void work(){ for(int i=0;it.eat(6),"李四").start(); new Thread(()->t.eat(2),"张三丰").start(); new Thread(()->t.eat(12),"赵六").start(); } }

12.5.4 ReentrantLock

ReentrantLock常常对比着synchronized来分析,我们先对比着来看然后再一点一点分析。

(1)synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。

(2)synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。

(3)synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以相应中断。

ReentrantLock好像比synchronized关键字没好太多,我们再去看看synchronized所没有的,一个最主要的就是ReentrantLock还可以实现公平锁机制。什么叫公平锁呢?也就是在锁上等待时间最长的线程将获得锁的使用权。通俗的理解就是谁排队时间最长谁先执行获取锁。

https://baijiahao.baidu.com/s?id=1648624077736116382&wfr=spider&for=pc

image-20210129143137509

  • 公平锁

    image-20210129143110008

    ReentrantLock
    
    /*
     * Copyright (c) 2006, 2021, webrx.cn All rights reserved.
     *
     */
    package cn.webrx;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 

    Project: untitled - T *

    Powered by webrx On 2021-01-31 19:16:40 *

    Created by IntelliJ IDEA *

    * @author webrx [webrx@126.com] * @version 1.0 * @since 15 */ public class T { Lock lock = new ReentrantLock(); void m1(){ lock.lock(); for(int i=0; i
关注
打赏
1665409997
查看更多评论
0.0492s