浅谈我对JAVA线程的了解

浅谈下我对JAVA线程的了解。


在讲线程的时候, 我该先讲讲进程 。


那么什么是进程 ?

大家在使用window系统的时候,肯定用过一个功能叫 “ 任务管理器 ”, 在任务管理器里,就有一项叫进程的选项,点进去一探究竟,会发现,

在进程的列表内容里,那里显示着一条又一条运行程序信息, 原来呀,进程就是一个正在执行的程序。


那么什么是线程 ?

其实,线程是进程的一个独立控制单元,线程是控制着进程的执行。一个进程里,至少有一个线程或多个线程。


实例: 进程就好像公司,每家公司一定有个BOSS , 随着公司的日益壮大,BOSS一个人管理不来了,

             他就会请外援,帮助管理公司,当然这些是后话了。  我想说的是线程就是那个BOSS  ——

             不知道大家对于我的举例有没感觉不适合,我个人理解是这样哒,嘿嘿。


既然了解了进程和线程的关系,现在说说JAVA中线程的表现形式:

首先,在java.lang包下,有个名叫 Thread 类, 这就是线程类。 创建线程有2种方式 —— 


第一种方式:

class ThreadTest extends Thread {    // 1. 定义一个类,继承 Thread 类

	public void run() {          // 2. 复写 Thread 类中的run方法
		System.out.println("It is my create thread .");
	}

	public static void main(String[] args) {
		
		ThreadTest t = new ThreadTest();  //3. 实例化定义的类
		t.start();			  //4. 调用父类的start()方法。
	}
}

第二种方式:

class ThreadTest implements Runnable {   // 1. 定义一个类,实现Runnable接口
	
	public void run() {              // 2. 复写 Runnable 接口的run方法
		System.out.println("It is my create thread .");
	}

	public static void main(String[] args) {	
		ThreadTest t = new ThreadTest();  //3. 实例化定义的类
		Thread thread = new Thread(t);    //4. 创建线程对象,传入定义的类对象。  
		thread.start();			  //5. 调用线程类的start()方法。
	}
}


创建线程2种方式的区别在于:

继承方式:有局限性,JAVA只支持单继承

实现方式:避免了单继承的局限性,同步共享数据及处理。

所以得出的结论是,创建线程使用实现方式,也就是上面的第二种方式。


引进多线程,现在来谈谈它的好处 :

本来一个搬货,现在来了一群人来搬货,答案显而易见, 当然一群人更快搬完货。

这里,就可以得出结论,高效,提高了效率。


俗话说的好, 有利就有弊 ——  多线程也不例外,现在来谈谈它的坏处:


坏处一:共享数据错误

class ThreadTest implements Runnable 
{	
	/*	下面演示卖票的小程序,已知有3个窗口在售票,总共10张票。 */
	
	private int ticket = 10;
	public void run()
	{   
		while(ticket>0)
		{
			try{ Thread.sleep(10); }
			catch (Exception e) { e.toString(); }

			if(ticket>0)
			{
				System.out.println(Thread.currentThread().getName()+"......."+ticket--);
			}
		}             
		
	}

	public static void main(String[] args) 
	{	
		ThreadTest t = new ThreadTest(); 

		Thread t1 = new Thread(t,"NO-1");
		Thread t2 = new Thread(t,"NO-2");  
		Thread t3 = new Thread(t,"NO-3");      
		
		t1.start();
		t2.start();
		t3.start();

		/*
		print:
			NO-2.......10
			NO-3.......8
			NO-1.......9
			NO-2.......7
			NO-3.......6
			NO-1.......7
			NO-2.......5
			NO-3.......5
			NO-1.......5
			NO-2.......4
			NO-3.......2
			NO-1.......3
			NO-2.......1
			NO-3.......1
			NO-1.......1

			从结果发现, 同一样的票,3个线程都有可能同时卖出去了。
			这导致了共享数据的错误,其实是不允许这种事情发生的。
		*/
	}
}

其实,造成这样的问题,原因是数据没有同步,JAVA知道这种问题后提供了一个专业的解决方式,叫同步。


什么是同步呢 ?

假设你要上厕所,你会先敲门看看有没人 , 噢 ~ 有人,我等。

                                                                              哦 ~ 没人,我进去,并且锁上门,等我上完厕所了,我要解锁才能出门。

  

假设有一所房子,有个门,你要想进去,你随意 —— ,但是你进去了必须锁门,不能给别人再进来,

只有你出去的时候,把锁解开了,你才可以出去,换别人进来,这种方式在JAVA就叫同步。


同步的关键字是 :  synchronized 


下面演示同步的使用:

	public void run()
	{   
		while(ticket>0)
		{
			try{ Thread.sleep(10); }
			catch (Exception e) { e.toString(); }
			
			synchronized(ThreadTest.class)
			{
				if(ticket>0)
				{
					System.out.println(Thread.currentThread().getName()+"......."+ticket--);
				}
			}
		}             
	}


同步的说明:

1. 被同步所包含的,也就是同步代码块里面的内容,这些内容就是需要被同步的。

2. 同步函数有一个形参,该形参代表一个锁,当线程读到该同步函数时,同步会判断里面是否有其他线程,

    如何没有,则拿着锁进去,并且锁上,等执行完后,释放锁,该程序才完成。

3. 同步的形参可以是任意对象,可通过创建Object obj来使用,

4. 必须要有2个或2个以上的线程,才能使用同步函数。 (否则没意义)


同步有2种表现形式,请看以下实例:

//1. 同步在函数上,同步为标记形式
	public synchronized void method_1()
	{
		while(ticket>0)
		{
			try{ Thread.sleep(10); }
			catch (Exception e) { e.toString(); }

			if(ticket>0)
				System.out.println(Thread.currentThread().getName()+"......."+ticket--);
		}             
	}

	public void method_2()
	{
		while(ticket>0)
		{
			try{ Thread.sleep(10); }
			catch (Exception e) { e.toString(); }

			//2. 同步在函数内,同步为函数形式
			synchronized(ThreadTest.class)
			{
				if(ticket>0)
					System.out.println(Thread.currentThread().getName()+"......."+ticket--);
			}
		}                         
	}

这里需要注意的是,同步作为标记形式的时候:

非静态函数的锁是: this , 也就是当前对象。

    静态函数的锁是: 类名.class




坏处二:线程中的死锁

同步也有一个小BUG, 那就是引发死锁 ,那什么是死锁呢 ?

其实就是同步嵌套同步,

示例: A和B在吃饭,可是每人只有一支筷子,2个人都想吃饭,于是A跟B要筷子,可是B也跟A要筷子,

             2个人都互不让步,结果谁也没吃上饭 。  这种互不让步的状态,就是死锁了。


下面是死锁的示例:

class MyLock
{
<span style="white-space:pre">	</span>static Object locka = new Object();
<span style="white-space:pre">	</span>static Object lockb = new Object();
}


class ThreadTest implements Runnable 
{<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>private boolean flag;


<span style="white-space:pre">	</span>ThreadTest(boolean flag)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>this.flag = flag; 
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>public void run()
<span style="white-space:pre">	</span>{   
<span style="white-space:pre">		</span>if(flag)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>synchronized(MyLock.locka)
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>System.out.println("if --- locka");
<span style="white-space:pre">				</span>synchronized(MyLock.lockb)
<span style="white-space:pre">				</span>{
<span style="white-space:pre">					</span>System.out.println("if --- lockb");
<span style="white-space:pre">				</span>}
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>}else
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>synchronized(MyLock.lockb) 
<span style="white-space:pre">			</span>{
<span style="white-space:pre">				</span>System.out.println("else --- lockb");
<span style="white-space:pre">				</span>synchronized(MyLock.locka)
<span style="white-space:pre">				</span>{
<span style="white-space:pre">					</span>System.out.println("else --- locka");
<span style="white-space:pre">				</span>}
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>public static void main(String[] args) 
<span style="white-space:pre">	</span>{<span style="white-space:pre">	</span>
<span style="white-space:pre">		</span>Thread t1 = new Thread(new ThreadTest(true));
<span style="white-space:pre">		</span>Thread t2 = new Thread(new ThreadTest(false));  
 
<span style="white-space:pre">		</span>t1.start();
<span style="white-space:pre">		</span>t2.start();
<span style="white-space:pre">	</span>}
}


在实际的开发中,我们要尽可能的避免死锁。


----------------------------------------------------------------------------------------------------------------------------------


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值