您的位置:首页 > 编程语言 > Java开发

java笔记-多线程-线程安全

2014-07-28 16:23 295 查看
多线程概述:

/*
** 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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: