实现线程的方式是一,继承Thread类,重写父类的run()方法
二,实现接口Runnable中的run()方法。
下面是简单的例子
例子1:银行存取钱问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | package com.direct.demo; public class Bank { private static int money; public int getMoney(){ return money; } public void saveMoney( int m){ synchronized ( this ) { System.out.println( "存钱后的总金额:" +(money+=m)); } } public void drawMoney( int m){ synchronized ( this ) { Bank bank = new Bank(); if (bank.getMoney()<= 0 ) { System.out.println( "没得钱,取个pi" ); } else { System.out.println( "取钱后剩的总金额:" +(money-=m)); } } } public static void main(String[] args) { Man m1 = new Man(); Women w = new Women(); Thread t1 = new Thread(m1); Thread t2 = new Thread(m1); Thread t3 = new Thread(m1); Thread t4 = new Thread(w); Thread t5 = new Thread(w); Thread t6 = new Thread(w); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); } } class Man implements Runnable{ private Bank bank = new Bank(); public void run() { int m = 100 ; int i= 0 ; while (i< 5 ) { bank.saveMoney(m); i++; try { Thread.sleep( 100 ); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Women implements Runnable{ private Bank bank = new Bank(); public void run() { int m = 100 ; int i= 0 ; //bank.getMoney()>0 while (i< 5 ) { bank.drawMoney(m); try { Thread.sleep( 100 ); } catch (InterruptedException e) { e.printStackTrace(); } i++; } } } |
例子2:生产者与消费者问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | package com.direct.demo; public class Clerk { private int product = - 1 ; //这个方法由生产者调用 public synchronized void setProduct( int product){ if ( this .product != - 1 ) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this .product = product; System.out.printf( "生产者设定 (%d)%n" , this .product); notify(); } //这个方法由消费者调用 public synchronized int getProduct(){ if ( this .product==- 1 ) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } int p = this .product; System.out.printf( "消费者取走 (%d)%n" , this .product); this .product = - 1 ; notify(); return p; } public static void main(String[] args) { Clerk clerk = new Clerk(); new Thread( new ProducerInt(clerk)).start(); new Thread( new ConsumerInt(clerk)).start(); } } class ProducerInt implements Runnable{ private Clerk clerk; public ProducerInt(Clerk clerk){ this .clerk = clerk; } public void run() { System.out.println( "生产者开始生产整数了.................." ); for ( int product = 1 ; product <= 10 ; product++) { try { Thread.sleep(( int )Math.random()* 300 ); } catch (InterruptedException e) { e.printStackTrace(); } clerk.setProduct(product); } } } class ConsumerInt implements Runnable{ private Clerk clerk; public ConsumerInt(Clerk clerk){ this .clerk = clerk; } public void run() { System.out.println( "消费者开始消耗整数........" ); for ( int i = 1 ; i <= 10 ; i++) { try { Thread.sleep(( int )Math.random()* 300 ); } catch (InterruptedException e) { e.printStackTrace(); } clerk.getProduct(); //从店员取走整数 } } } |
例子3:购票窗口实现票数同步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | package com.direct.demo; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ThreadTicket { public static void main(String[] args) { Booking b1 = new Booking( "军人售票口" ); Booking b2 = new Booking( "学生售票口" ); Booking b3 = new Booking( "老年人售票口" ); Booking b4 = new Booking( "网上售票口" ); b1.start(); b2.start(); b3.start(); b4.start(); } } /* * 多窗口卖票系统。多线程 * 票数为静态的,共享数据 * synchronized(对象){}代码块中的内容是加锁的, * 即当一个线程在使用时,其他线程不可以进入。 * 使得共享资源数据的安全。 */ class Booking extends Thread{ public Booking(String name){ super (name); } static int ticket = 50 ; //票数共50张 Lock lock = new ReentrantLock(); //明锁 * Lock是个接口,只能实例化它的子类 * 明锁适合高并发,上万 * 暗锁适合并发率不高时,效率高 */ //重写run方法, public void run(){ while (ticket> 0 ){ synchronized (Booking. class ) { if (ticket> 0 ) { System.out.println( super .getName()+ "窗口---->卖出的车票号No." +ticket); ticket--; } else { System.out.println( super .getName()+ "票已售罄!!!" ); } try { sleep( 100 ); //睡100毫秒,抛出多线程异常 } catch (InterruptedException e) { e.printStackTrace(); } } /*lock.lock();//加锁,锁定以下代码 if (ticket>0) { System.out.println(super.getName()+"卖票:"+ticket); ticket--; }else { System.out.println(super.getName()+"票已售罄!!!"); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } lock.unlock();//解锁 */ } } } |
/*
* ReentrantLock根据传入构造方法的布尔型参数实例化出Sync的实现类FairSync和NonfairSync
* ,分别表示公平的Sync和非公平的Sync。
* 由于ReentrantLock我们用的比较多的是非公平锁
ReentrantLock 和synchronized 均为重入锁
* 1. ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。
2. ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
3. ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。
对ReentrantLock的可重入锁这篇博客使用简单的例子进行讲解, http://blog.csdn.net/yanyan19880509/article/details/52345422
例子4:线程中sleep()和wait()方法测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | package com.direct.demo; public class TestSleepaWait { public static void main(String[] args) { new Thread( new Thread1()).start(); try { Thread.sleep( 5000 ); } catch (InterruptedException e) { e.printStackTrace(); } new Thread( new Thread2()).start(); } } class Thread1 implements Runnable{ public void run() { synchronized (TestSleepaWait. class ) { System.out.println( "Thread1 is start........" ); System.out.println( "Thread1 is wait.............." ); try { //调用wait方法,线程会放弃对象锁,进入等待对象的等待锁定池 TestSleepaWait. class .wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println( "Thread1 is go on........" ); System.out.println( "Thread1 is over!" ); } } } class Thread2 implements Runnable{ @Override public void run() { synchronized (TestSleepaWait. class ) { System.out.println( "Thread2 is enter.........." ); System.out.println( "Thread2 is sleep......." ); //只有针对对象调用notify()方法后本线程才进入对象锁定池 //准备获取对象进入运行状态 TestSleepaWait. class .notify(); //=============== //如果把上句注释掉。即对象锁调用了wait方法,但是没有调用notify //程序就一致处于挂起状态 try { Thread.sleep( 5000 ); //sleep方法暂停执行时间,让出CPU,监控状态保持, //时间到 了就回复运行, 不会释放对象锁 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println( "Thread2 is going on.........." ); System.out.println( "Thread2 is over!!!!" ); } } } |
例子5:sleep()实现对象存取值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | package com.direct.demo; public class ThreadCom { public static void main(String[] args) { Person person = new Person(); new Thread( new Producer(person)).start(); new Thread( new Consumer(person)).start(); } } class Person{ private String name = "张杰" ; private String sex = "男" ; public synchronized void put(String name,String sex){ this .name = name; this .sex = sex; try { Thread.sleep( 100 ); } catch (InterruptedException e) { e.printStackTrace(); } } //方法加锁 public synchronized void get(){ System.out.println(name+ "----->" +sex); try { Thread.sleep( 100 ); } catch (InterruptedException e) { e.printStackTrace(); } } } class Consumer implements Runnable{ Person person; public Consumer(Person person){ this .person = person; } public void run() { while ( true ){ person.get(); } } } class Producer implements Runnable{ Person person; public Producer(Person person){ this .person = person; } public void run() { int i = 0 ; while ( true ) { if (i== 0 ) { person.put( "谢娜" , "女" ); } else { person.put( "张杰" , "男" ); } i = (i+ 1 )% 2 ; //奇数和偶数 } } } |
例子6:死锁发生条件
在写代码时要避免死锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | package com.direct.demo; public class DeadLock { public static void main(String[] args) { ThreadLock tl = new ThreadLock( true ); ThreadLock tl2 = new ThreadLock( false ); new Thread(tl).start(); new Thread(tl2).start(); } } /* * 死锁的产生条件: * 1、至少一个资源共享 * 2、至少有一个线程(任务),必须持有资源,且等待获取别的线程持有的资源 * 3、任务抢不到资源 * 4、必须有无限循环 * (1) 互斥条件:一个资源每次只能被一个进程使用。 * (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 * (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 * (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 * 举例说明:不可剥夺资源A、B,进程C、D * 不可剥夺资源:一个进程申请了之后,不能强制收回,只能进程结束之后自动释放。内存是可剥夺资源 * 进程C申请了资源A,进程D申请了资源B。 * 接下来进程C的操作需要用到资源B,进程D的操作需要用到资源A * 但是C、D都得不到资源,就引发了死锁 */ class Lock{ static Object lockOne = new Object(); //资源A static Object lockTwo = new Object(); //资源B } class ThreadLock implements Runnable{ private boolean flag; public ThreadLock( boolean flag){ this .flag = flag; } @Override public void run() { if (flag){ while ( true ) { synchronized (Lock.lockOne) { System.out.println( " this is lockOne" ); synchronized (Lock.lockTwo) { System.out.println( "this is lockTwo" ); } } } } else { while ( true ) { synchronized (Lock.lockTwo) { System.out.println( " 这是 lockTwo" ); synchronized (Lock.lockOne) { System.out.println( "这是 lockOne" ); } } } } } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· 语音处理 开源项目 EchoSharp
· 《HelloGitHub》第 106 期
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 使用 Dify + LLM 构建精确任务处理应用