java之涉足线程

来源:互联网 发布:如何创建软件 编辑:程序博客网 时间:2024/05/02 13:14

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

进程:直译就是正在进行中的程序。

线程:就是进程中一个负责程序执行的控制单元 

      一个进程可以有多执行路径,称之为多线程

      一个进程至少有一个线程。

多线程的好处: 解决了部分同时运行的问题

多线程的弊端: 线程太多会倒效率的降低

其实应用程序的执行都是cpu在做着快速的切换完成的 这个切换是随机的

如果创建一个线程?

方式一 继续Thread

步骤 :1 定义一个类继续Thread类 

       2 覆盖Thread类中的run方法。

       3 直接创建Thread的子类对象创建线程。

例如:

class Demo extends Thread
{
 private String name;
 Demo(String name)
 {
  super(name);
  // this.name = name;
 }
 public void run()
 {
  for (int x = 0; x < 10; x++)
  {
  // for(int y=-9999999; y<999999999; y++){}
   System.out.println(name + "....x=" + x + ".....name="
    + Thread.currentThread().getName());
  }
 }
}
class ThreadDemo2
{
 public static void main(String[] args)
 {
  Thread t1 = new Thread();
  Demo d1 = new Demo("旺财");
  Demo d2 = new Demo("xiaoqiang");
  d1.start();// 开启线程,调用run方法。
  d2.start();
  System.out.println("over...." + Thread.currentThread().getName());
 }
}

jvm创建的主线程的任务都是定义在了主函数中。

run()方法中定义就是线程要运行的人物代码。

创建时就明确了名称的定义

Thread 通过getName()来获取线程的名称。Thread编号从0开始。

主线程的名字就是main

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

定义类实现Runnable接口  

覆盖接口中的run方法,将线程的人物代码封装在run()中

3通过Thread类创建线程对象,并将Runnable接口的子类对象作为构造函数的参数进行传递

例如:

class Bank
{
 private int sum;
 // private Object obj = new Object();
 public synchronized void add(int num)// 同步函数
 {
  // synchronized(obj)
  // {
  sum = sum + num;
  // -->
  try {
   Thread.sleep(10);
  } catch (InterruptedException e) {
  }
  System.out.println("sum=" + sum);
  // }
 }
}
class Cus implements Runnable
{
 private Bank b = new Bank();
 public void run()
 {
  for (int x = 0; x < 3; x++)
  {
   b.add(100);
  }
 }
}
class BankDemo
{
 public static void main(String[] args)
 {
  Cus c = new Cus();
  Thread t1 = new Thread(c);
  Thread t2 = new Thread(c);
  t1.start();
  t2.start();
 }
}

为什么这样做?因为线程的任务都封装在Runnable接口子类对象中的方法中,所以要在线程对象创建时就必须明确要运行的任务。

调用线程对象的start方法开启线程。

Runnable她的出现仅仅是将线程的任务进行了对象的封装。

实现了Runnable接口的好处:

 1 将线程的任务从线程的子类中分离出来,进行了单独的封装

   按照了面向对象的思想将任务封装成对象

 2 避免了java单继承的局限性。

创建线程的第二种方式最常用。

多次启动一个线程是非法的。

线程安全问题产生的原因

1 多个线程在操作共享数据

2 操作共享数据的线程代码有多条。

当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算 

就会导致线程安全问题的产生。

解决思路:

就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,

其他线程是不可以参与运算的

必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。

java中,用同步代码块就是可以解决这个问题

同步代码块的格式

synchronized(对象){

    需要同步的代码:

}

同步的好处就是: 解决了线程安全的问题

      弊端就是:相对降低了效率,因为同步的外线程的都会判断同步锁。

同步的前提:必须有多个线程并使用同一个锁。

同步函数和同步代码的锁是this

同步函数和同步代码块的区别:

同步代码块的锁是任意对象 

同步函数的锁是固定的 this

建议使用同步代码。

静态的同步函数使用的锁是 该函数所属字节码文件对象, 可以用getClass方法获取,也可以用当前类名.class表示。

//懒汉式   面试经常面试到的

class single{

  private static finall Single s=null

  privat single{

    }

  public static Single getInstance(){

      ifs==null{ //第一次判断是为了提高效率 

         synchronizedSingleclass{//解决安全隐患。

             ifs==null{

                  s=new Single();

                }

            }

       }

       return s

 }

}

线程常见的问题之一:死锁。

同步的嵌套。

/*

死锁:常见情景之一:同步的嵌套。

*/

class Ticket implements Runnable
{
 private int num = 100;
 Object obj = new Object();
 boolean flag = true;
 public void run()
 {
  if (flag)
   while (true)
   {
    synchronized (obj)
    {
     show();
    }
   }
  else
   while (true)
    this.show();
 }
 public synchronized void show()
 {
  synchronized (obj)
  {
   if (num > 0)
   {
    try {
     Thread.sleep(10);
    } catch (InterruptedException e) {
     System.out.println(Thread.currentThread().getName()
       + ".....sale...." + num--);
    }
   }
  }
 }
 class DeadLockDemo
 {
  public static void main(String[] args)
  {
   Ticket t = new Ticket();
   // System.out.println("t:"+t);
   Thread t1 = new Thread(t);
   Thread t2 = new Thread(t);
   t1.start();
   try {
    Thread.sleep(10);
   } catch (InterruptedException e) {
   }
   t.flag = false;
   t2.start();
  }
 }
}

 

等待 唤醒机制

涉及的方法。

1 wait() 让线程处于冻结状态,被wait的线程会被存储到线程池中。

2 notify()唤醒线程池中的一个任意线程

3 notifyAll()唤醒线程池中的所有线程

这些方法都必须定义在同步中

因为这些方法是用于操作线程状态的方法

必须要明确到底操作的是哪个锁上的线程。

为什么操作线程的方法wait notify notifyAll定义在了object类中?

因为这些方法是监视器的方法。监视器其实就是锁。

jdk 1.5出现了 lock 替代了synchronized

jdk 1.5出现以后将同步和锁封装成了对象,并将操作的隐式定义到了该对象中,将隐式动作变成了显示动作。

lock接口:出现替代了同步代码块或者同步函数。将同步代码的隐式锁操作变成了显示锁操作。

 同时更为灵活可以一个锁上加上多组监视器

 lock():获取锁

 unlock():释放锁,通常需要定义finally代码块中。

Condition接口: 出行替代了Object中的wait notify notifyAll 方法。

             将这些监视器方法单独进行了封装,变成了Condition监视器对象。

             可以任意锁紧组合。

await();

signal();

signalAll();

wait sleep 区别

1wait可以指定时间也可以不指定。

  sleep必须要指定时间

在同步中时,多cpu的执行权和锁的处理不同

 wait:释放行权,释放锁

 sleep:释放执行权,不释放锁。

我的总结:Java线程是Java语言中一个非常重要的部分通过使用Java5线程新特征的API,可以很容易的做出复杂的多线程程序。

 

 

---------------------- (科技新时代)申请入驻搜狐公众平台,特此声明----------------------

 

 

0 0
原创粉丝点击