java笔记-多线程-线程安全
2014-07-28 16:23
295 查看
多线程概述:
若创建对象直接调用run方法,不调研那个start则相当于对象直接调用方法,没有启动线程。程序执行时仍然是main线程,先执行完run方法中的for循环后再执行main中的for循环。
多线程实例:
线程的四种状态:
获取线程名称:
多线程的安全问题:
静态同步代码块:
延迟加载的单例设计模式
线程死锁
/* ** 1.进程: ** 是一个这在执行中的程序,每一个进程执行都有一个顺序,该顺序是一个执行路径,或者叫控制单元。 ** 2.线程: ** 就是进程中一个独立的控制单元,线程控制着进程的执行; ** java虚拟机启动时,会有一个进程java.exe. ** 该进程中,至少有一个线程,负责着java程序的执行; ** 3.如何自定义一个线程? ** java中thread类已经提供了对该事物的描述。 ** 创建线程的第一种方式: ** a.定义类继承Thread。 ** b.复写Thread类中的run方法。 ** c.调用线程的start方法: ** 调用该方法有两个作用:启动线程,调用run方法。 ** 多线程的运行结果每次都不同: ** 多个线程都获取cpu的执行权,cpu执行到谁,谁就执行 ** 在某一个时刻,只能有一个程序在运行(多核除外) ** cpu在进行着快速切换,速度非常快。 ** 我们可以形象的把多线程的运行形容为在抢占cpu的执行权。 ** 这也是多线程的一个特想:随机性;谁抢到谁执行,至于执行多长时间,cpu说了算。 */ //定义一个继承自线程Thread的类; class Demo extends Thread{ //重写run方法; //为什么重写run方法? //thread类用于描述线程,该类定义了一个功能,用于存储线程要运 //行的代码,该存储功能就是run方法; //run方法定义线程要运行的代码。 public void run(){ //Main线程和Demo线程交替运行如下语句; for(int x=0;x<400;x++){ System.out.println("---Demo Thread Run::"+x); } } } class ThreadDemo{ public static void main(String[] args){ Demo newThread=new Demo(); //调用start方法,启动线程并执行run方法; newThread.start(); //Main线程和Demo线程交替运行如下语句; for(int y=0;y<400;y++){ System.out.println("+++Main Thread Run!::"+y); } } }
若创建对象直接调用run方法,不调研那个start则相当于对象直接调用方法,没有启动线程。程序执行时仍然是main线程,先执行完run方法中的for循环后再执行main中的for循环。
多线程实例:
/* ** 实现两个线程和主程序交替运行。 */ class Demo extends Thread{ String name; Demo(String name){ this.name=name; } public void run(){ for(int y=0;y<100;y++){ System.out.println(name+"\tchildren thread run!"+y); } } } class ThreadDemo2{ public static void main(String[] args){ Demo d_1=new Demo("-----d_1"); //为便于区分,传递线程标识 Demo d_2=new Demo("-----d_2"); //为便于区分,传递线程标识 d_1.start(); d_2.start(); for(int x=0;x<100;x++){ System.out.println("Main thread run!"+x); } } }
线程的四种状态:
获取线程名称:
/* ** 获取线程名称; ** this.getName(); ** Thread.currentThread(); */ class Demo extends Thread{ String name; Demo(String name){ //this.name=name; super(name); //向父类传递线程名参数,设置线程名; } public void run(){ for(int y=0;y<100;y++){ System.out.println(Thread.currentThread()+"\tchildren thread run!"+y); //System.out.println(name+"\tchildren thread run!"+y); } } } class ThreadDemo2{ public static void main(String[] args){ Demo d_1=new Demo("-----d_1"); //为便于区分,传递线程标识 Demo d_2=new Demo("-----d_2"); //为便于区分,传递线程标识 d_1.start(); d_2.start(); for(int x=0;x<100;x++){ System.out.println(this.getName()+"Main thread run!"+x); } } }售票实例(线程的第二种实现方式)
/* ** 售票程序. ** 引出实现线程的第二种方法: ** 1.定义类实现Runable接口; ** 2.覆盖Runnable接口中的Run方法; ** 3.通过Thread类建立线程对象; ** 4.将Runnable接口的的对象作为实际参数传递给Thread类的构造函数 ** 自定义run方法所属的对象是Runnable接口的子类对象,要让线程 ** 去执行指定对象的run方法,就必须明确该run方法所属的对象。 ** 5.调用Thread类的start方法,并运行Runnable接口类的Run方法。 */ /* ** 实现方式和继承方式的区别: ** 实现方式:避免了单继承的局限性; ** 继承Thread:线程代码存放在Thread子类的run方法中。 ** 实现Runnable:线程代码存放在Runnable接口的子类的run方法中。 ** 在定义线程时,建议使用实现方式; */ class Demo implements Runnable{ private static int tickets=300; //将线程要运行的代码放在run方法中。 public void run(){ while(true){ if(tickets>0){ System.out.println(Thread.currentThread().getName()+"\tsale ticket::"+tickets--); } } } } class TicketDemo{ public static void main(String[] args){ //创建Runnable接口类的对象; Demo d=new Demo(); //将Runnable接口类的对象作为实际参数传递给Thread线程的构造函数; Thread t1=new Thread(d); Thread t2=new Thread(d); Thread t3=new Thread(d); Thread t4=new Thread(d); //启动start函数; //由于t1~t4的四个线程共用Runnable接口类的run方法。 t1.start(); t2.start(); t3.start(); t4.start(); } }
多线程的安全问题:
/* ** 1.Thread.sleep(10)的使用导致共享数据tickets出现错误。 ** 当多条语句在操作同一个线程共享数据时,一个线程正在运行该多条语 ** 句处理共享数据,但还没有执行完,另一个线程参与进来执行,导致共** 享数据错误。 ** 2.解决办法: ** 操作共享数据时,只允许一个线程执行共享数据的操作,在执行过程 ** 中,其它线程不得参与。 ** 3.java对于多线程的安全问题提供了专业的解决方式。 ** 同步代码块 synchronized(对象){需要被同步的代码} */ class Demo implements Runnable{ Object obj=new Object(); private static int tickets=300; //将线程要运行的代码放在run方法中。 public void run(){ while(true){ //同步代码块; synchronized(obj){ if(tickets>0){ try{ //sleep函数定义了该函数可能抛出异常; //但函数run并未定义抛出异常信息,需手动处理此处可能的异常; Thread.sleep(1); } catch(Exception e){} System.out.println(Thread.currentThread().getName()+"\tsale ticket::"+tickets--); } } } } } class ThreadSafe{ public static void main(String[] args){ //创建Runnable接口类的对象; Demo d=new Demo(); //将Runnable接口类的对象作为实际参数传递给Thread线程的构造函数; Thread t1=new Thread(d); Thread t2=new Thread(d); Thread t3=new Thread(d); Thread t4=new Thread(d); //启动start函数; //由于t1~t4的四个线程共用Runnable接口类的run方法。 t1.start(); t2.start(); t3.start(); t4.start(); } }
静态同步代码块:
/* ** 1.如何找问题? ** a.明确哪些代码是多线程运行代码; ** b.明确共享数据; ** c.明确多线程运行代码中哪些是操作共享数据的。 ** ** 2.同步函数即在函数上声明synchronized,run方法不可声明; ** 3.同步函数用的是哪个锁? ** 函数需要被对象调用,那么函数都有一个所属对象引用,就是this ** 所以同步函数使用的锁是this。 ** 4.如果同步函数被静态修饰后,使用的锁是什么? ** 静态进内存,内存中没有本类对象,但是一定有该类对应的字节码文件对象。 类名.class 该对象的类型是class ** 静态同步函数的锁是:该方法所在类的字节码文件对象,即:类名.class */ class Demo implements Runnable{ Object obj=new Object(); private static int tickets=300; boolean flag=true; //将线程要运行的代码放在run方法中。 public void run(){ //if else验证了同步代码块和同步函数的锁是否具有同样效果,若效果相同则同步代码块的锁正确,否则异常。 if(flag){ while(true){ //同步代码块; //静态同步代码块的锁是该方法所在类的字节码文件对象。 synchronized(Demo.class){ //此处同步代码块中的参数若为this仍然有异常数值0出现。 if(tickets>0){ try{ //sleep函数定义了该函数可能抛出异常; //但函数run并未定义抛出异常信息,需手动处理此处可能的异常; Thread.sleep(10); } catch(Exception e){} System.out.println(Thread.currentThread().getName()+"\t-----sale ticket::"+tickets--); } } } } else{ while(true){ show(); } } } public static synchronized void show(){ if(tickets>0){ try{ //sleep函数定义了该函数可能抛出异常; //但函数run并未定义抛出异常信息,需手动处理此处可能的异常; Thread.sleep(10); } catch(Exception e){} System.out.println(Thread.currentThread().getName()+"\t+++++sale ticket::"+tickets--); } } } class StaticThread{ public static void main(String[] args){ //创建Runnable接口类的对象; Demo d=new Demo(); //将Runnable接口类的对象作为实际参数传递给Thread线程的构造函数; Thread t1=new Thread(d); Thread t2=new Thread(d); //启动start函数; //由于t1~t4的四个线程共用Runnable接口类的run方法。 t1.start(); try{Thread.sleep(10);}catch(Exception e){} d.flag=false; t2.start(); } }
延迟加载的单例设计模式
//多线程,延迟加载的单例设计模式: //懒汉式 class Single{ private static Single s=null; private Single(){}; public static Single getInstance(){ if(s==null){ //本锁为所在的字节码文件对象; synchronized(Single.class){ if(s==null){ //延迟加载的对象。 s=new Single(); } } } return s; } }
线程死锁
//死锁 //实现自Runnable的类,用于创建多线程。 class Demo implements Runnable{ boolean flag; Demo(boolean flag){ this.flag=flag; } //重写Runnable实现中的run方法; public void run(){ System.out.println("Thread"); //判断两个线程的特定标识; if(flag){ //线程进入锁定对象不同。 synchronized(objClass.lockA){ //若线程t1进入,则锁定lockA。 System.out.println("if lockA."); //线程t1执行到此处,执行权若被t2夺走,并且t2锁定了lockB,则发生死锁。 synchronized(objClass.lockB){ System.out.println("if lockB."); } } } else{ //线程进入锁定对象不同。 synchronized(objClass.lockB){ //若线程t2进入,则锁定lockB。 System.out.println("else lockB."); //线程t2执行到此处,执行权若被t1夺走,并且t1锁定了lockA,则发生死锁。 synchronized(objClass.lockA){ System.out.println("else lockA."); } } } } } class objClass{ static Object lockA=new Object(); //创建Object对象。 static Object lockB=new Object(); //创建Object对象。 } class DeadLock{ public static void main(String[] args){ //Demo d=new Demo(); //创建线程并传递线程特定标识flag值。 Thread t1=new Thread(new Demo(true)); Thread t2=new Thread(new Demo(false)); //启动线程并执行run方法; t1.start(); t2.start(); } }
相关文章推荐
- 黑马程序员--Java学习笔记之多线程(自定义线程的两种方式对比、线程状态、线程安全)
- 【我的Java笔记】多线程_使用Lock锁对象解决线程安全问题
- java多线程学习笔记2
- Java多线程笔记
- Java多线程编程总结笔记——六线程的同步与锁
- C\C++ 程序员从零开始学习Android - 个人学习笔记(十) - java基础 - 多线程(待续)
- java多线程笔记
- java学习笔记(九)----多线程
- 学习java多线程的笔记3-使用BlockingQueue阻塞队列来模拟两个线程之间的通信
- Java多线程编程总结笔记——五线程状态的转换
- Java多线程编程总结笔记——二概念与原理
- 黑马程序员---java多线程 学习笔记
- JAVA学习笔记之多线程
- java笔记8多线程
- [零散篇]Java学习笔记---Java的Socket网络编程以及多线程
- Java学习笔记---多线程
- java多线程学习笔记3
- corejava笔记1 多线程
- JAVA多线程学习笔记
- Java多线程实现--笔记1