java学习【知识点及代码15】
来源:互联网 发布:mmm互助平台源码下载 编辑:程序博客网 时间:2024/05/16 01:24
1:多线程(理解)
(1)线程是依赖于进程而存在的。
A:进程 正在运行的应用程序B:线程 进程的执行路径,执行单元
(2)多线程的两种方案:(掌握)
请参照:多线程两种方式继承Thread类(查看api简单介绍Thread类):
package com.edu_02;public class MyThread extends Thread{ //1.继承Thread类 //2.重写run方法,重写run方法中的代码之后,当我们启动了这个线程之后,我们的这个线程就会执行run方法中的代码 @Override public void run() { //需求:开启该线程之后,执行一个for循环 for (int i = 0; i < 10; i++) { System.out.println(i); } } }
package com.edu_02;public class Test { public static void main(String[] args) { //只要我们创建了一个线程对象,并且启动该线程的实例,我们就相当于开启了一个线程 MyThread mt = new MyThread(); mt.start();//1.开启了一个线程 2.让开启的这个线程执行他对应的类中的run方法 //再次创建一个子线程,并开启这个子线程执行他的run方法 MyThread mt2 = new MyThread(); mt2.start(); }}
实现Runable接口:
package com.edu_03;public class MyThread implements Runnable{ @Override public void run() { //启动该线程对象之后,需要执行的代码 for (int i = 0; i < 10; i++) { System.out.println(i); } }}
package com.edu_03;public class Test { public static void main(String[] args) { //创建Mythread对象 MyThread mt = new MyThread(); //开启这个线程 //mt.start();//这里的这个类仅仅是实现了Runnalble接口的一个类,但是start方法在Thread类中 //但是我们想要开启一个线程,就必须调用start方法,请问怎么办? //public Thread(Runnable target) Thread t1 = new Thread(mt); t1.start(); }}
(3)多线程的几个问题:
A:启动线程用的是哪个方法 start()B:start()和run()的区别 start():1.开启线程 2.执行run()方法里面的代码 run():执行的是线程里面执行的代码,并不会开启线程C:为什么要重写run() 因为每个线程需要执行的代码都是都是不一样的, 我们需要将每个线程自己独立执行的代码写到run()方法中执行D:线程可以多次启动吗如果是不同的线程对象,是可以同时开启的
package com.edu_04;public class Test { public static void main(String[] args) { //B:start()和run()的区别 // 创建一个线程对象 MyThread mt = new MyThread(); MyThread mt2 = new MyThread(); //mt.start();//1.首先开启了一个独立的线程 2.让这个独立的线程执行run方法中的代码 System.out.println("--------"); //mt.run();//1.普通的创对象,调方法 2.代码实在主线程执行,不会开辟新线程 //D:线程可以多次启动吗 mt.start(); //mt2.start();//如果是不同的线程对象,是可以同时开启的 //mt.start();//线程是不能多次启动的 }}
package com.edu_04;public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(i); } }}
(4)线程的调度和控制
线程休眠(Thread.sleep(毫秒值))线程名称(setName(),getName();)线程的调度及优先级setPriority(10)(注意默认值是5,区间在1-10之间)什么叫线程优先级:说白了就是设置你抢占cpu执行权抢占到的概率
package com.edu_05;public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { //线程休眠(Thread.sleep(毫秒值)) try { Thread.sleep(1000);//在此处出现的异常我们只能抓取,不能抛出 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //获取执行线程的姓名 System.out.println(this.getName()+i); } }}
package com.edu_05;public class Test { public static void main(String[] args) { //线程名称(setName(),getName();) //创建3个线程对象 MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread(); //给三个线程设置姓名 t1.setName("刘备"); t2.setName("张飞"); t3.setName("关羽"); //设置线程的优先级 //线程的调度及优先级setPriority(10)(注意默认值是5,区间在1-10之间) //t1.setPriority(100);//设置的区间必须在1-10之间 t1.setPriority(10); //开启线程 t1.start(); t2.start(); t3.start(); }}
package com.edu_06;public class MyThread implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { //首先调用方法获取到执行该run方法的线程对象,然后调用方法获取该线程对象的名称 System.out.println(Thread.currentThread().getName()+":"+i); } }}
package com.edu_06;public class Test { public static void main(String[] args) { //创建三个线程并且启动三个线程 MyThread mt = new MyThread(); //创建线程对象 Thread t1 = new Thread(mt); Thread t2 = new Thread(mt); Thread t3 = new Thread(mt); //给线程设置姓名 t1.setName("刘备"); t2.setName("关羽"); t3.setName("张飞"); //启动线程 t1.start(); t2.start(); t3.start(); }}
(5)多线程案例(两种方式实现,睡一会出现线程安全问题):
5.1继承Thread卖票
package com.edu_07;public class Test { public static void main(String[] args) { //创建三个线程模拟三个售票窗口 MyThread mt1 = new MyThread(); MyThread mt2 = new MyThread(); MyThread mt3 = new MyThread(); //给线程设置名称 mt1.setName("窗口一"); mt2.setName("窗口二"); mt3.setName("窗口三"); //启动线程,开启售票 mt1.start(); mt2.start(); mt3.start(); }}
package com.edu_07;public class MyThread extends Thread{ //共有100张票,将ticket改为静态之后,被类的所有对象所共享 static int ticket = 100; @Override public void run() { //用一个while true循环模拟三个窗口一直处于打开的状态 while (true) { //只有当ticket>0的时候,才可以出售票 if (ticket>0) { System.out.println(getName()+"正在出售第:"+ticket--+"张票"); } } }}
5.2实现Runnable卖票(睡一会出现线程安全问题)
package com.edu_08;public class Test { public static void main(String[] args) { //创建MyThread这个对象 MyThread mt = new MyThread(); //创建3个窗口 Thread t1 = new Thread(mt); Thread t2 = new Thread(mt); Thread t3 = new Thread(mt); //给线程对象设置名称 t1.setName("窗口一"); t2.setName("窗口二"); t3.setName("窗口三"); //启动窗口开始售票 t1.start(); t2.start(); t3.start(); }}
package com.edu_08;public class MyThread implements Runnable{ int ticket = 100; @Override public void run() { while (true) { if (ticket>0) { System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票"); } } }}
问题:按照真实的情景加入了延迟,却发现出现了这样的两个问题: A:相同的票卖了多次 CPU的一次操作必须是原子性的(操作是CPU执行一次就可以直接完成的) B:出现了负数的票 随机性和延迟导致的出现上面的问题称为线程安全问题。
package com.edu_09;/** * 总结:什么时候会出现线程安全问题? * 1.存在多线程的情况 * 2.多个线程之间存在共享数据 * 3.存在多条语句操作共享数据 * * 在我们自己的程序中存在线程安全问题吗?存在。。 * 1.存在多线程的情况 * 存在 * 2.多个线程之间存在共享数据 * 存在 * 3.存在多条语句操作共享数据 * 存在 * * * 如何解决线程安全问题?? * 1.存在多线程的情况 * 改不了 * 2.多个线程之间存在共享数据 * 改不了 * 3.存在多条语句操作共享数据 * 可以改变 * * *(7)如何解决多线程安全问题(掌握) 注意:线程安全执行效率就低,线程不安全,执行效率高 A:同步代码块(测试不是同一个锁的情况,测试是同一个锁的情况) synchronized(对象) { 需要被同步的代码。 } * 1.对象? * 答:任意对象,这个对象就被成为锁 * 2.需要被同步的代码? * 答:会出现线程安全问题的代码。 * 3.注意:同步代码块对这个锁是有要求的 * 答:需要多个线程共享同一把锁 */public class MyThread implements Runnable{ //定义100张票 int ticket = 100; Object obj = new Object(); @Override public void run() { while (true) { //同步代码块 //synchronized (new Object()) {//t1,t2,t3三个线程不共享同一把锁,每个线程都有自己的一把锁 synchronized (obj) {//这样3个线程才可以共享同一把锁 if (ticket>0) { //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果 try { Thread.sleep(100); /** * 分析:为什么会出现两张100张票 * CPU的一次操作必须是原子性的(操作是CPU执行一次就可以直接完成的) * t1抢占到cpu的执行权,此时ticket=100,但是此刻休眠了 * 此时被t2抢占到了cpu的执行权,此时ticket=100, * t1,t2分别睡了100毫秒之后,分别醒来了。。 * t1此时出售第100张票 * t2此时出售第100张票 */ /** * 分析:为什么会出现0张票和-1张票 * 假设此时票池中仅剩1张票了, * t1进来休眠了 * t2进来休眠了 * t3进来休眠了 */ } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票"); /** * t1醒来,出售的是第1张票,此时tickt=0 * t2醒来,出售第0张票,此时ticket=-1 * t3醒来,出售第-1张票,此时ticket=-2 */ /** * ticket--这个动作一共包含几步: * 1.打印出ticket此刻本身的值 * 2.ticket自减1 * 3.将自减之后的ticket的最新的值赋值给变量ticket */ } } //当被同步的代码执行完毕之后,t1手里拿着的obj这个锁才会被释放, //t1,t2,t3重新抢占cpu的执行权,谁抢到了继续拿着obj这个锁,执行同步代码块中的内容 } }}
package com.edu_09;public class Test { public static void main(String[] args) { //创建MyThread对象 MyThread mt = new MyThread(); //创建三个窗口 Thread t1 = new Thread(mt); Thread t2 = new Thread(mt); Thread t3 = new Thread(mt); //给每一个窗口设置姓名 t1.setName("窗口一"); t2.setName("窗口二"); t3.setName("窗口三"); //开启窗口进行售票 t1.start(); t2.start(); t3.start(); }}
(6)多线程安全问题
A:是否是多线程环境B:是否有共享数据C:是否有多条语句操作共享数据
(7)如何解决多线程安全问题(掌握)
线程安全执行效率就低A:同步代码块(测试不是同一个锁的情况,测试是同一个锁的情况) synchronized(对象) { 需要被同步的代码。 } 需求:1.测试不是同一把锁的时候线程安全吗? 2.如果是同一把锁线程安全吗?两个问题:1.对象是什么 ? 答:任意对象 ,相当于是一把锁,只要线程进去就把锁锁上 2.需要同步的代码? 答:被线程执行的代码C:锁对象问题 a:同步代码块(定义一个抽象类,里面专门定义一个锁) 任意对象 b:同步方法(仅适用于实现runable接口) public synchronized void sellTicket(){同步代码} this c:静态同步方法 类的字节码对象 public static synchronized void sellTicket() { 需要同步的代码 }
package com.edu_10;public class MyThread implements Runnable{ //定义100张票 static int ticket = 100; Object obj = new Object(); int x = 0; @Override public void run() { while (true) { if (x%2==0) { synchronized (MyThread.class) {//这样3个线程才可以共享同一把锁 if (ticket>0) { //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果 try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票"); } } }else { sellTicket(); } x++; } }// private void sellTicket() {// synchronized (obj) {//这样3个线程才可以共享同一把锁 // if (ticket>0) {// //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果// try {// Thread.sleep(100);// } catch (InterruptedException e) {// // TODO Auto-generated catch block// e.printStackTrace();// }// // System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票");// }// }// } //同步方法:同步方法是将synchronized关键字加到方法上,同步方法的锁是this// private synchronized void sellTicket() { // if (ticket>0) {// //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果// try {// Thread.sleep(100);// } catch (InterruptedException e) {// // TODO Auto-generated catch block// e.printStackTrace();// }// // System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票");// // }// } //静态同步方法,他的锁是本类的字节码文件对象:类名.class。 private static synchronized void sellTicket() { if (ticket>0) { //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果 try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票"); }}}
package com.edu_10;public class Test { public static void main(String[] args) { //创建MyThread对象 MyThread mt = new MyThread(); //创建三个窗口 Thread t1 = new Thread(mt); Thread t2 = new Thread(mt); Thread t3 = new Thread(mt); //给每一个窗口设置姓名 t1.setName("窗口一"); t2.setName("窗口二"); t3.setName("窗口三"); //开启窗口进行售票 t1.start(); t2.start(); t3.start(); }}
(8)匿名内部类的方式使用多线程(掌握)
new Thread() { public void run() { ... } }.start(); new Thread(new Runnable(){ public void run() { ... } }).start();
package com.edu_11;public class NiMingThread { public static void main(String[] args) { //方式1: new Thread(){ //重写的方法 @Override public void run() { for (int i = 0; i <10; i++) { System.out.println(i); } } }.start(); //方式2 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i <10; i++) { System.out.println(i); } } }).start(); }}
案例:利用匿名内部类,启动多个线程,验证单例设计模式之懒汉式所存在的缺陷,当使用多线程来搞的时候就不单例了。
package com.edu_12;public class Test { public static void main(String[] args) { //启动第一个线程 new Thread(){ @Override public void run() { System.out.println(SingleIntanceDemo.getInstance()); //com.edu_12.SingleIntanceDemo@2d7fc1e7 } }.start(); //启动第二个线程 new Thread(){ public void run() { System.out.println(SingleIntanceDemo.getInstance()); //com.edu_12.SingleIntanceDemo@2a8b83e3 }; }.start(); }}
package com.edu_12;/** * 面试中单例设计模式,我们该写哪一个? * 懒汉 * * 工作中我们用的时候,用哪个? * 饿汉 */public class SingleIntanceDemo { //私有化构造 private SingleIntanceDemo(){} private static SingleIntanceDemo instance = null; public synchronized static SingleIntanceDemo getInstance(){ try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (instance==null) { instance = new SingleIntanceDemo(); } return instance; }}
(9) JDK5的Lock锁,我们之前造的所有的锁都没有手动释放锁
static Lock lock = new ReentrantLock(); 枷锁:lock.lock(); 释放锁:lock.unlock(); 可以让我们明确的知道在哪里加锁和释放锁。 依然写一个卖票的demo,用lock枷锁释放锁, 为了保证我们创建的锁一定会被释放,用一下代码进行改进 try{....}finally{.....}
package com.edu_13;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class MyThread implements Runnable{ //定义100张票 int ticket = 100; Object obj = new Object(); //创建一个锁 Lock lock = new ReentrantLock(); @Override public void run() { while (true) { try{ //加上锁,获取锁 lock.lock(); if (ticket>0) { //考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果 try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票"); } }finally{ //这里面的代码一定会被执行 //释放锁 lock.unlock(); } } }}
package com.edu_13;public class Test { public static void main(String[] args) { //创建MyThread对象 MyThread mt = new MyThread(); //创建三个窗口 Thread t1 = new Thread(mt); Thread t2 = new Thread(mt); Thread t3 = new Thread(mt); //给每一个窗口设置姓名 t1.setName("窗口一"); t2.setName("窗口二"); t3.setName("窗口三"); //开启窗口进行售票 t1.start(); t2.start(); t3.start(); }}
(10)死锁问题
同步嵌套,锁里面套了一个锁,出现同步嵌套(简单介绍,要求大家以后写的时候需要注意)
package com.edu_14;public class DieThread extends Thread{ boolean flag; //提供一个有参构造 public DieThread(boolean flag){ this.flag = flag; } @Override public void run() { if (flag) { synchronized (MyLock.objA) { System.out.println("if"+"objA"); synchronized (MyLock.objB) { System.out.println("if"+"objB"); } } }else { synchronized (MyLock.objB) { System.out.println("else"+"objB"); synchronized (MyLock.objA) { System.out.println("else"+"objA"); } } } }}
package com.edu_14;public abstract class MyLock { //定义两个锁 public static final Object objA = new Object(); public static final Object objB = new Object();}
package com.edu_14;public class Test { public static void main(String[] args) { //创建两个线程,分别设置不同的布尔值 DieThread dt = new DieThread(true); DieThread dt2 = new DieThread(false); //开启两个线程 dt.start(); dt2.start(); }}
(11)线程等待和唤醒机制(案例演示:waitThread,NotifyThread,MyLock,Test)
锁对象调用wait()锁对象调用notify()
注意: wait和sleep的区别 线程等待,在等待的同时释放锁,而sleep()方法在执行的过程中是不会释放锁的
package com.edu_15;public class Test { public static void main(String[] args) { //创建等待线程,让等待线程处于一个等待状态 WaitThread wt = new WaitThread(); wt.start(); //睡上5秒钟之后唤醒等待线程 try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //创建唤醒线程对象 NotifyThread nt = new NotifyThread(); nt.start(); }}
package com.edu_15;public abstract class MyLock { public static final Object obj = new Object();}
package com.edu_15;public class NotifyThread extends Thread{ @Override public void run() { synchronized (MyLock.obj) { //唤醒等待线程 MyLock.obj.notify();//唤醒正在等待的线程,唤醒的等待线程的锁对象,必须和等待线程的锁对象一致 } }}
package com.edu_15;public class WaitThread extends Thread{ @Override public void run() { synchronized (MyLock.obj) { //让等待线程处于等待状态 try { MyLock.obj.wait();//当线程处于等待状态的时候,线程就不会继续往下执行了 //线程在处于等待的时候,会释放掉自己手中的锁 //sleep()这个方法,在线程休息的时候会释放锁码? //答:不会 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("我被唤醒了"); }}
阅读全文
0 0
- java学习【知识点及代码15】
- Java学习【知识点及代码4.1】
- Java学习【知识点及代码5】
- Java学习【知识点及代码6】
- Java学习【知识点及代码7】
- Java学习【知识点及代码8】
- Java学习【知识点及代码9】
- java学习【知识点及代码10】
- java学习【知识点及代码11】
- java学习【知识点及代码12.1异常】
- java学习【知识点及代码12.2】
- java学习【知识点及代码13】
- java学习【知识点及代码14】
- java学习【知识点及代码16】
- java学习【知识点及代码17】
- java学习【知识点及代码18】
- JAVA学习代码——知识点
- 常用代码及知识点集合
- C++之函数参数默认值
- Html5斜45度地图+3D模型ARPG系列教程(2)-- 相机更随及平滑
- PAT排名汇总
- jetty和tomcat的区别和关系
- 安装YII框架
- java学习【知识点及代码15】
- 获取广告在页面中的坐标
- 宏面积
- Android----网络图片游览器
- 云计算IaaS的核心技术:虚拟化技术
- Java学习笔记_13
- aquid代理
- 微信WeToast增强插件
- [学习笔记]认识Android Service