黑马程序员_多线程与死锁

------- android培训java培训、期待与您交流! ----------

 

一、线程的创建

1、继承Thread类

创建步骤:
1、定义类继承Thread
2、复写Thread类中的run方法
3、调用线程的start方法
此方法有两个作用:
启动线程
调用run()方法


 

class Demo extends Thread//定义类继承Thread
{
public void run()//复写run()方法
{
for(int x=0; x<60; x++)
System.out.println("Demo run()---"+x);
}
}
class ThreadDemo
{
public static void main(String[] args)
{
Demo d = new Demo();//创建一个线程
d.start();//开启线程,并调用线程的run()方法

for(int x=0; x<60; x++)
System.out.println("Hello Thread!---"+x);
}
}

程序运行结果如下:

 
 
运行结果每一次都不同。
因为多个下次都要获取CPU的执行权,CPU执行到谁,谁就运行。
但是在某一时刻,只能有一个程序在运行。(多核除外)
多线程的一个特性,随机性。

2、实现Runnable接口


 

/*
需求:简单的卖票程序,多个窗口同是卖票。

创建线程的第二种方式:实现Runnable接口

步骤:
1、定义类实现Runnable接口
2、覆盖Runnable接口中的run方法。
将线程要运行的代码存放在该run方法中。
3、通过Thread类建立线程对象。
4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
5、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。


*/
class Ticket implements Runnable
{

private int tick = 100;
public void run()
{
while (true)
{
if(tick>0)
{
System.out.println(Thread.currentThread().getName()+"---sale : "+tick--);
}
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket t = new Ticket();

Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);

t1.start();
t2.start();
t3.start();
t4.start();
}
}

程序运行结果如下:
黑马程序员_多线程 - freedomheaven - freedomheaven的博客

3、两种方法对比


实现方式和继承方式有什么区别?

实现方式好处:避免了单继承的局限性。
在定义线程时,建议使用实现方式。

两种方式区别:
继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable:线程代码存放在接口的子类的run方法中。

二、多线程的安全问题

1、通过分析上述程序,发现存在安全隐患,可以通过代码进行验证。


 

class Ticket implements Runnable
{

private int tick = 100;
public synchronized void run()
{
while (true)
{
if(tick>0)
{
//因为继承了接口,而接口中没有异常的抛出,所以只能try
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"---sale : "+tick--);
}
}
}
}

修改后运行结果出现以下情况:

 
黑马程序员_多线程 - freedomheaven - freedomheaven的博客
出现问题原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还未执行完,另一个线程就进入执行,从而导致共享数据出错。

2、JAVA对多线程安全问题有专业解决方式:同步代码块。
synchronized(对象)
{
 需要被同步的代码
}

具体代码如下:

 


 

class Ticket implements Runnable
{
 //Object obj = new Object();
 
 private int tick = 1000;
 public void run()
 {
  while (true)
  {
   synchronized(this)
   {
    if(tick>0)
    {
     //因为继承了接口,而接口中没有异常的抛出,所以只能try
     try{Thread.sleep(10);}catch(Exception e){}
     System.out.println(Thread.currentThread().getName()+"---sale  : "+tick--);
    }
   }
  }
 }
}
class TicketDemo2
{
 public static void main(String[] args)
 {
  Ticket t = new Ticket();

 

  Thread t1 = new Thread(t);
  Thread t2 = new Thread(t);
  Thread t3 = new Thread(t);
  Thread t4 = new Thread(t);
  Thread t5 = new Thread(t);
  
  t1.start();
  t2.start();
  t3.start();
  t4.start();
  t5.start();
  
 }
}


代码修改后,运行结果中未出现为0等错误情况。

好像是CPU的缘故,在票数1000的时候,只能看到一个线程。当票数为10000的时候,方可看到其他线程运行的情况。


 

3、单例设计模式

 


 

/*
单例设计模式

 

*/
//饿汗式
class Single
{
 private static final Single s = new Single();
 private Single(){}
 public static Single getInstance()
 {
  return s;
 }
}

 

//懒汉式

//延迟加载单例模式
class Single
{
 private static Single s = null;
 private Single(){}
 public static Single getInstance()
 {
  synchronized(Single.class)//通过锁确保程序在多线程访问时运行安全
  {
   if(s==null)
    s = new Single();
  }
  return s;
 }
}

 

发现懒汉式中,如果有一个线程进入锁中,其它线程只能等待,会导致程序效率低,继续对其进行完善。

 

 

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;
 }
}


 

 

三、死锁的探讨

 

 

/*
死锁形成探讨
*/
class Test implements Runnable
{
 private boolean flag;
 Test(boolean flag)//建立标识,让两个线程分别运行。
 {
  this.flag = flag;
 }
 public void run()//锁相互嵌套,形成各自占用资源,同时需要对方资源。
 {
  if (flag)
  {
   synchronized(MyLock.LockA)
   {
    System.out.println("if LockA");
    synchronized(MyLock.LockB)
    {
     System.out.println("if LockB");
    }
   }
  }
  else
  {
   synchronized(MyLock.LockB)
   {
    System.out.println("else LockB");
    synchronized(MyLock.LockA)
    {
     System.out.println("else LockA");
    }
   }
  }
 }
}
class MyLock//创建两个锁
{
 static Object LockA = new Object();
 static Object LockB = new Object();
}
class DeadLockDemo
{
 public static void main(String[] args)
 {
  Thread t1 = new Thread(new Test(true));//创建线程t1
  Thread t2 = new Thread(new Test(false));//创建线程t2

  t1.start();
  t2.start();
 }
}


程序运行结果如下:

 
黑马程序员_多线程 - freedomheaven - freedomheaven的博客
可见:两个线程分别只运行了第一输出语句,便形成了死锁。
 

----------- android培训java培训、期待与您交流! --------------   

详细请查看:http://edu.youkuaiyun.com/heima/

下载方式:https://pan.quark.cn/s/b4d8292ba69a 在构建食品品牌的市场整合营销推广方案时,我们必须首先深入探究品牌的由来、顾客的感知以及市场环境。 此案例聚焦于一款名为“某饼干产品”的食品,该产品自1998年进入河南市场以来,经历了销售业绩的波动。 1999至2000年期间,其销售额取得了明显的上升,然而到了2001年则出现了下滑。 在先前的宣传活动中,品牌主要借助大型互动活动如ROAD SHOW来吸引顾客,但收效甚微,这揭示了宣传信息顾客实际认同感之间的偏差。 通过市场环境剖析,我们了解到消费者对“3+2”苏打夹心饼干的印象是美味、时尚且充满活力,但同时亦存在口感腻、价位偏高、饼身坚硬等负面评价。 实际上,该产品可以塑造为兼具美味、深度创新性的休闲食品,适宜在多种情境下分享。 这暗示着品牌需更精确地传递产品特性,同时消解消费者的顾虑。 在策略制定上,我们可考虑将新产品原有的3+2苏打夹心进行协同推广。 这种策略的长处在于能够借助既有产品的声誉和市场占有率,同时通过新产品的加入,刷新品牌形象,吸引更多元化的消费群体。 然而,这也可能引发一些难题,例如如何合理分配新旧产品间的资源,以及如何保障新产品的独特性和吸引力不被既有产品所掩盖。 为了提升推广成效,品牌可以实施以下举措:1. **定位修正**:基于消费者反馈,重新确立产品定位,突出其美味、创新共享的特性,减少消费者感知的缺陷。 2. **创新宣传**:宣传信息应消费者的实际体验相契合,运用更具魅力的创意手段,例如叙事式营销,让消费者体会到产品带来的愉悦和情感共鸣。 3. **渠道选择**:在目标消费者常去的场所开展活动,例如商业中心、影院或在线平台,以提高知名度和参度。 4. **媒体联...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值