线程 Thread Runnable start run

来源:互联网 发布:windows xp硬盘安装版 编辑:程序博客网 时间:2024/05/21 20:05

/*
 * 多线程的运行根据cpu的切换完成的。怎么切换cpu说了算
 * 所以多线程运行有一个随机性(cpu的快速切换造成的)。
 *
 * jvm中的多线程。
 * 至少有两个线程:一个是负责自定义代码运行的。这个从main方法开始执行的线程称之为主线程。
 *             一个是负责垃圾回收的。
 *            
 *通过实验,会发现每次结果都不一定相同,因为随机性造成的。
 *
 *而且每一个线程都有运行的代码内容。这个称之为线程的任务。
 *之所以创建一个线程就是为了去运行指定的任务代码。
 *
 *而线程的任务都封装在特定的区域中。
 *比如:
 *主线程运行的任务都定义在main方法中
 *垃圾回收线程在收垃圾都会运行finalize方法。
 */

/*建立线程:第一种方式
 * 查看API文档java.lang.Thread类。
 * 该类的描述中有创建线程的两种方式:
 * 一.继承Thread类
 *   1.继承Thread类。
 *   2.覆盖run方法。
 *   3.创建子类对象就是创建线程对象。
 *   4.调用Thread类中的start方法就可以执行线程。并会调用run方法。
 *
 *   start()开启线程后,都会执行run方法。说明run方法中存储的是线程要运行的代码。
 *   所以,自定义线程的任务代码都存储在run方法中
 *
 *  调用start和调用run方法的区别?
 *  调用start会开启线程,让开启的线程去执行run方法中的线程任务。
 *  直接调用run方法,线程并未开启,去执行run方法的只有主线程(main)
 */
class Demo2 extends Thread{
 private String name;
 Demo2(String name) //throws Exception
 {
//  if(!(name instanceof String))
//  {
//   throw new RuntimeException(name+"错误");
//  }
  this.name=name;
 }
 void show()
 {
  for(int x=0;x<10;x++)
  {
   System.out.println(name+"..."+x);
  }
 }
 public void run()   //线程要运行的代码
 {
  show();
 }
 
}
public class FinalizeDemo2 {
 public static void main(String[] args) {
  Demo2 d1 = new Demo2("jason");  //创建Thread子类对象就是创建线程对象
  Demo2 d2 = new Demo2("swift");
  d1.start();      //开始线程的开关:1.开启线程。2.让jvm虚拟机调用run方法
  d2.start();
 }
}
/*
建立线程的第二种方式。实现Runnable接口。
1,定义一个类实现Runnable。
2.覆盖Runnable接口中的run方法,将线程要运行的任务代码存储到该方法中。
3.通过Thread类创建线程对象,并将实现了Runnable接口的对象作为Thread类的构造函数的参数进行传递。
4。调用Thread类的start方法,开启线程。
实现Runnable接口的好处:
1.避免了继承Thread类的单继承的局限性。
2.Runnable接口出现更符合面向对象,将线程单独进行对象的封装。
3.Runnable接口出现,降低了线程对象和线程任务的耦合性。
!!!所以,以后创建线程都使用第二种方式。
*/
class SaleTicket2 implements Runnable//降低了线程对象和线程任务的耦合性
{
 private int tickets=100;
 public void run()
 {
  while(true)
  {
   if(tickets>0)
   {
    System.out.println(Thread.currentThread().getName()+"..普快.."+tickets--);
   }
     }
 }
}
//class SaleTicket2_1 implements Runnable//任务代码和线程子类解耦
//{
// private int tickets=100;
// public void run()
// {
//  while(true)
//  {
//   if(tickets>0)
//   {
//    System.out.println(Thread.currentThread().getName()+"..高铁.."+tickets--);
//   }
//     }
// }
//}
public class TicketDemo2
{
 public static void main(String[] args) {
  SaleTicket s = new SaleTicket();
//  SaleTicket2_1 s2= new SaleTicket2_1();
  
  Thread t1 = new Thread(s);   //多个线程处理一个共享资源(run方法)
  Thread t2 = new Thread(s);
//  Thread t3 = new Thread(s2);
//  Thread t4 = new Thread(s2);
  t1.start();
  t2.start();
//  t3.start();
//  t4.start();
 }
}

/*
如何停止线程?
原理:让run方法结束。
 线程任务通常都有循环。因为开启线程就是为了执行需要一些时间的代码。
 只要控制住循环,就可以结束run方法,就可以停止线程。
 控制循环弄个标记即可。定义变量

多线程的安全问题
运行结果会出现:0,-1,-2等
产生的原因:
1.线程任务中有处理到共享的数据
2.线程任务中有多条对共享数据的操作
一个线程在操作共享线程的过程中,其他线程参与了运算,造成了数据的错误。
解决思想:
只要保证多条操作共享数据的代码在某一时间段,被一条线程所执行,在执行期间不允许其他线程参与运算。
怎么能保证呢?
用到了同步代码块。只同步需要操作共享数据的代码块。
synchronized(对象)
{
需要被同步的代码块
}
同步在目前情况下保证了一次只能有一个线程在执行。其他线程进不来。
这就是同步的锁机制。解决了多线程的安全问题
有可能出现一种情况:
多线程安全问题出现后,加入同步机制,安全问题依旧!
这时肯定是同步出了问题。
只要遵守同步的前提,就可以解决。
同步的前提:
 多个线程在同步中必须使用同一个锁,这才是对多个线程同步。


/*
在ThreadTest6基础上,增加了同步函数。
同步函数,就是在函数上加上了同步关键字进行修饰。
同步表现形式有两种:1.同步代码块  2.同步函数
同步函数使用的锁是什么呢?函数需要被对象调用,哪个对象不确定,但是都用this来表示
同步函数使用的锁就是this
如果同步函数被static修饰呢?
static方法随着类加载,这时不一定有该类的对象。但是一定有一个该类的字节码文件对象。
这个对象简单的表示方式是  类名.class    Class是描述类和接口的类
同步函数和同步代码块的区别:
同步代码块使用的任意的对象作为锁。
同步函数只能使用this作为锁。
如果说:一个类中只需要一个锁,这时可以考虑同步函数,使用this,写法简单。
但是,一个类中如果需要多个锁,还有多个类中使用同一个锁,这时只能使用同步代码块。
建议使用同步代码块
*/
class Bank7
{
 private int sum;
 Object obj = new Object();
 public synchronized void add(int n)
 {
  sum=sum+n;
  try
  {
   Thread.sleep(10);
  }
  catch(InterruptedException e)
  {
   
  }
  System.out.println("sum="+sum);
 }
}
class Customer7 implements Runnable
{
 private Bank7 b = new Bank7();
 public void run()
 {
  for(int x=0;x<3;x++)
  {
   b.add(100);
  }
 }
}
public class ThreadTest7 {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
 }
}

/*
单例模式的并发访问
*/
//饿汉式      相对于多线程开发     安全!
//class Single{
// private static final  Single SINGLE_INSTANCE = new Single();
// private Single(){}
// public static Single getInstance()
// {
//  return SINGLE_INSTANCE;
// }
//}
//懒汉式(延迟加载模式)
/*
 在多线程并发访问时,会出现线程安全问题。
 加了同步就可以解决问题。无论是同步函数,还是同步代码块都行。
 但是效率降低了。
 可以通过if对单例对象的双重判断的形式。
 
*/
class Single{
 private static Single s=null;
 private Single(){}
// public static synchronized Single getInstance()
 public static Single getInstance()
 {
  if(s==null){
   synchronized(Single.class)//类的字节码文件对象
   {
    if(s==null)
    {
     s=new Single();
    }
    
   }
  }
  return s;
 }
}
class Demo8 implements Runnable
{
 public void run()
 {
  Single.getInstance();
 }
}
public class ThreadTest8 {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
 }
}

原创粉丝点击