java学习(15)
来源:互联网 发布:网络打印机ip地址查询 编辑:程序博客网 时间:2024/06/18 09:44
java学习(15)
1.多线程这篇开始写关于多线程的内容。
1.1线程是依赖于进程而存在的。
A:进程正在运行的应用程序
B:线程进程的执行路径,执行单元
1.2多线程的两种方案
方法一:继承Thread类,通过调用Thread类的start()方法,启动一个线程,
代码实现:
public class MyThreadTest extends Thread{@Overridepublic void run() {System.out.println("这是子线程的run方法");}}public static void main(String[] args) {//创建MyThreadTest对象MyThreadTest mt = new MyThreadTest();//启动线程mt.start();}
方法二:实现Runable接口,再通过Thread类的构造方法,把实现Runable接口的类对象传进去,再调用start()方法,启动线程,代码实现:
public class MyThreadTest implements Runnable{@Overridepublic void run() {System.out.println("这是子线程的run方法");}}public static void main(String[] args) {//创建MyThreadTest对象MyThreadTest mt = new MyThreadTest();//构造Thread对象Thread t = new Thread(mt);//启动线程t.start();}
1.3多线程的有关问题:
A:启动线程用的方法:start()
B:start()和run()的区别
start():
1.开启线程 2.执行run()方法里面的代码
run():执行的是线程里面执行的代码,并不会开启线程,简单来说,就是创建对象,调方法
C:重写run():因为需求不同
D:线程不可以多次启动
1.4线程的调度和控制
A.线程休眠:(Thread.sleep(毫秒值))--可以设置线程的休眠时间
Thread.sleep(500);//休眠500毫秒
B.线程名称:(setName(),getName();)--可以获取和设置线程的名称。对于实现了Runnable接口的类,调用Thread.currentThread().getName()来获取当前线程的名称。
//设置线程名称mt1.setName("ss1");mt2.setName("ss2");mt3.setName("ss3");
C.线程的调度及优先级(抢占cpu执行权抢占到的概率):setPriority(10)(注意默认值是5,区间在1-10之间)--可以设置线程的优先级
注意:设置了优先级,只能保证优先级高的线程抢占到CPU的概率大,但不是一定能抢到!!
//线程的调度及优先级setPriority(10)(注意默认值是5,区间在1-10之间mt1.setPriority(10);
1.5经典卖票案例
1.5.1继承Thread卖票
public class MyThread extends Thread{ int ticket = 20;@Overridepublic void run() {while(true){//判断票数if(ticket>0){System.out.println(this.getName()+"正在卖"+ticket--+"张票");}}}}public static void main(String[] args) {//创建mythreadMyThread mt1 = new MyThread();MyThread mt2 = new MyThread();MyThread mt3 = new MyThread();//线程名称(setName(),getName();)mt1.setName("窗口一");mt2.setName("窗口二");mt3.setName("窗口三");//启动线mmt1.start();mt2.start();mt3.start();}
1.5.2实现Runnable卖票
public class MyThread implements Runnable{int ticket = 20;@Overridepublic void run() {while(true){//判断票数if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖"+ticket--+"张票");}}}}public static void main(String[] args) {//创建mythreadMyThread mt = new MyThread();//创建Thread对象Thread t1 = new Thread(mt);Thread t2 = new Thread(mt);Thread t3 = new Thread(mt);//线程名称(setName(),getName();)t1.setName("窗口一");t2.setName("窗口二");t3.setName("窗口三");//启动线mt1.start();t2.start();t3.start();}分析:按照真实的情景加入了延迟后,发现出现了这样的两个问题:
A:相同的票卖了多次
B:出现了负数的票
原因:(1)CPU的一次操作必须是原子性的(操作是CPU执行一次就可以直接完成的)
(2)线程抢占随机性和延迟导致的
1.6多线程安全问题分析:
A:是否是多线程环境B:是否有共享数据
C:是否有多条语句操作共享数据
1.7解决多线程安全问题:线程安全执行效率就低,这里对于各种方法,对上述代码进行部分改写。
(1)同步代码块(测试不是同一个锁的情况,测试是同一个锁的情况)
synchronized(对象) {
需要被同步的代码。
}
分析:这里的对象是一个任意对象 ,相当于是一把锁,只要线程进去就把锁锁上:
需要同步的代码就是被线程执行的代码。对象是同一个的时候,线程安全:对象不是同一个的时候,线程不安全。上述代码块可以这么改写,这样就不会出现线程安全问题:
public class MyThread implements Runnable{int ticket = 100;//创建锁对象Object obj = new Object();@Overridepublic void run() {while(true){synchronized(obj){try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//判断票数if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖"+ticket--+"张票");}}}}}
(2)锁对象问题
a:同步代码块(定义一个抽象类,里面专门定义一个锁)
public abstract class MyLock {//定义锁public static final Object obj = new Object();}
b:同步方法(仅适用于实现runable接口)锁是:this
public synchronized void sellTicket(){
同步代码
}
//同步方法:同步方法是将synchronized关键字加到方法上,//同步方法的锁是thisprivate synchronized void sellTicket() {try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//判断票数if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖"+ticket--+"张票");}}
c:静态同步方法锁是:类的字节码对象
public static synchronized void sellTicket() {
需要同步的代码
}
//静态同步方法,他的锁是本类的字节码文件对象:类名.classpublic static synchronized void sellTicket(){try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//判断票数if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖"+ticket--+"张票");}}
1.8匿名内部类的方式使用多线程
new Thread() {
public void run() {
...
}
}.start();
new Thread(new Runnable(){
public void run() {
...
}
}).start();
示例:
//方法一new Thread(){@Overridepublic void run() {System.out.println("方法一的线程");}}.start();//方法二new Thread(new Runnable() {@Overridepublic void run() {System.out.println("方法二的线程");}}).start();
1.9 JDK5的Lock锁:我们之前造的所有的锁都没有手动释放锁
static Lock lock = new ReentrantLock();
加锁:lock.lock();
释放锁:lock.unlock();
1.10死锁问题:同步嵌套,锁里面套了一个锁,出现同步嵌套对上面代码改写:
public class MyThread implements Runnable{int ticket = 100;//static Lock lock = new ReentrantLock();static Lock lock = new ReentrantLock();@Overridepublic void run() {while(true){try {//加锁:lock.lock();lock.lock();//判断票数if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖"+ticket--+"张票");}}finally{//释放锁:lock.unlock();lock.unlock();}}}}
示例:
public class MyLock {//定义两个锁public static final Object objA = new Object();public static final Object objB = new Object();}
1.11线程等待和唤醒机制public class Deadlock extends Thread{boolean flag;//有参的构造方法public Deadlock(boolean flag){this.flag = flag;};//run方法@Overridepublic void run() {if(flag){synchronized(MyLock.objA){System.out.println("if"+"MyLock.objA锁");synchronized(MyLock.objB){System.out.println("if"+"MyLock.objB锁");}}}else{synchronized(MyLock.objB){System.out.println("else"+"MyLock.objB锁");synchronized(MyLock.objA){System.out.println("else"+"MyLock.objA锁");}}}}}
锁对象调用wait()
唤醒对象调用notify()
示例:
public abstract class MyLock {//定义锁public static final Object obj = new Object();}public class NotifyThread extends Thread{@Overridepublic void run() {//唤醒等待线程synchronized(MyLock.obj){MyLock.obj.notify();}}}public class WaitThread extends Thread{@Overridepublic void run() {synchronized(MyLock.obj){try {MyLock.obj.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(this.getName()+"唤醒了");}}public static void main(String[] args) {//创建线程对象WaitThread wt = new WaitThread();//设置名称wt.setName("awakeThread");//让进程等待wt.start();//2秒后唤醒try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//唤醒对象调用notify()//创建唤醒线程对象NotifyThread nt = new NotifyThread();nt.start();}运行:
注意:wait()线程等待,在等待的同时释放锁,而sleep()方法在执行的过程中是不会释放锁的
- java学习(15)
- java学习(15)
- 【java】java学习(一)
- 【java】java学习(二)
- Java学习笔记18天---(15)
- 我的java学习日记(15)
- java入门学习(15)—多线程
- Java学习笔记15
- java学习笔记15
- Java学习笔记15
- Java学习-15天
- Java学习15 泛型
- Java学习笔记(15)--Java String类详解(二)
- Java学习(途径!)
- 学习JAVA(一)
- 学习Java(一)
- java学习(1)
- java学习(2)
- uva 10340
- 04-树7 二叉搜索树的操作集 (30分)
- 对log工具类的方法封装
- 神奇的一句话引发的思考
- 用OpenCV读取图像并且显示
- java学习(15)
- 数据库中存储日期的字段类型到底应该用varchar还是datetime
- Leetcode 求买股票的最大盈利问题
- WannaCryptor 勒索蠕虫样本深度技术分析
- webpack代码部署index.html无内容显示
- orale 多行合并为一行
- Android 判断一个字符串是否含有中文
- 微信小程序点击添加移除class
- 关于VMware tools的使用安装 超详细