多线程

进程就是应用程序的执行实例,有独立的内存空间和系统资源。

进程的特点:

1、是动态产生,动态销完的,动态的占用,动态的释放     2、是并发执行的      3、进程是独立

线程是进程内部的独立单元,在同一个进程里可以运行多个线程,然后使用的资源是它的进程的资源,cpu不会再单独给线程资源,它也可以单线独立执行,它是进程中执行运算的最小单位,真正在cpu上运行的是线程。线程同时执行的原理是线程抢占cpu的资源,同一个时间,只有一个线程在执行,其他的线程都在等待的状态,只是因为时间比较短,看到现象就是同时执行。一个线程可以创建一个线程,也可以删除一个线程。

线程分为:1、系统级的线程,就是系统分配的进程    2、用户级线程,程序来控制它的存亡,存在于用户空间

进程中至少包含一个线程,这叫主线程,在程序开始运行的时候就会创建的,但是可以创建其他的线程,我们创建的都不是主线程

什么是多线程:如果在一个进程同时运行了多个线程,用来完成不同的工作,则称之为“多线程”。

main()方法即为主线程入口。

方法:

线程对象.getName()      获得当前线程的对象的名字

Thread.currentThread()      得到当前线程对象

.setPriority(int  newPriority)      更改线程的优先级,1~10,越高的优先执行的越快,1最低,默认优先级为5

sleep(long millis)         在指定的毫秒数内记当前正在执行的线程休眠,这是一个静态方法

jion()               让此线程强制执行完,才让其他的线程执行

yield()             暂停当前正在执行的线程对象,可执行其他线程,但是也不排除执行此线程,因为要看哪个线程抢到了cpu资源,这是静态方法

interrupt()             中断线程

isAive()              测试线程是否处于活动状态

调用run()方法,只有主线程一条执行路径

调用start()方法,多条线程执行路径

要创建线路就是要重写run方法,线程要做的事,都写在run方法里面。

步骤:

1、创建线程类,定义线程

2、创建线程类对象(使用Runnable接口实现,就要多使用Thread创建一个对象,将之前创建的线程类对象作为参数,放进线程中)

3、启动线程start方法,系统会帮程序创建一个线程,会调用run方法,如果是接口实现的线程,要使用创建的Thread对象去启动线程

4、终止线程

线程的创建:

1、继承java.lang.Thread类,Thread类也是实现Runnable接口的,所以一般比较简单的线程,就使用Thread类

相对于Runnable来说,比较简便,缺点是不可以再继承其他的类了,在Thread中,run方法里,如果给的对象为空的时候,run方法就不会执行

案例1:

package cn.lnm.exp1;
/**
 * 这个是使用继承Thread类,去实现线程
 * @author Administrator
 *
 */
public class MyThread extends Thread {
 @Override

//要去重写Thread类中的run方法,达到执行线程的操作,要实现线程操作的代码都是要写到run方法中的,或者写一个方法,然后在run方法中去调用此方法
 public void run() {
  for (int i = 0; i <10; i++) {
   //Thread.currentThread().getName()这个是获得当前线程的名字
   System.out.println(Thread.currentThread().getName()+" "+i);
  }
 }
 public static void main(String[] args) {
  //main方法是一条主线程,要在主线程中去启动其他的线程
  MyThread t1=new MyThread();
  t1.start();//要使用start()方法去实现线程的启动
  MyThread t2=new MyThread();
  t2.start();
 }
}

2、实现java.lang.Runnable接口 

多个线程可以共享一个资源(线程类对象)

案例2:

package cn.lnm.exp1;

public class MyRunnable implements Runnable{

 @Override  public void run() {  

   for (int i = 0; i < 10; i++) {    

    System.out.println(Thread.currentThread().getName()+" "+i);  

     }   

   }  

  public static void main(String[] args) {   

    MyRunnable m1=new MyRunnable();   

    Thread t1=new Thread(m1);   

    t1.start();   

    Thread t2=new Thread(m1);   

    t2.start();  

    }

}

 线程的同步:多个线程共享同一资源时,一个线程未完成全部操作的时候,其他线程修改的数据,造成数据不安全问题。可以使用同步代码块,或者同步方法(将run方法的代码块抽取出一个方法,使用synchronized去做修饰,再到run方法中去调用此方法),把会发生数据不一致的地主,加一把锁,让只有一个线程进去,让其他线程处于等待状态。

synchronized修饰的线程都是安全的,效率会低,但是会数据安全,比如Hashtable、StringBuffered这些类都是线程安全的。

synchronized就是为当前的线程声明一个锁,当一个线程完成全部操作,其他线程才能进入。

案例3:这是锁定方法

package cn.lnm.exp1;

/**  

* 火车票  

* @author Administrator

 *

 */

public class Ticket implements Runnable{  

private int count=10;//记录剩余票数  

private int num=0;//记录当前第几张票

 @Override

 public void run() {  

 qiang();

 }  

public synchronized void qiang() {  

 while(true){

//循环    当剩余票数为0时结束   

 if(count<=0){//如果剩余票数小于0就跳出循环     

break;    

}   

 //修改数据(剩余票数,抢到第几张票)    

count--;    

num++;    

//网络延迟,使用线程休眠    

try {    

 Thread.sleep(500);    

} catch (InterruptedException e) {    

 e.printStackTrace();   

 }    

//显示信息,反馈用户抢到第几张票   

 System.out.println("抢到第"+num+"票,剩余"+count+"张票");   

}  

}

}

案例4:这是锁定代码块

@Override
 public void run() {
  while (true) {// 循环 当剩余票数为0时结束
   synchronized (this) {
    if (count <= 0) {// 如果剩余票数小于0就跳出循环
     break;
    }
    // 修改数据(剩余票数,抢到第几张票)
    count--;
    num++;
    // 网络延迟,使用线程休眠
    try {
     Thread.sleep(500);
    } catch (InterruptedException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    // 显示信息,反馈用户抢到第几张票
    System.out.println("抢到第" + num + "票,剩余" + count + "张票");
   }
  }
 }

 多个并发线程访问同一资源的同步代码块时

  1.同一时刻只能有一个线程进入synchronized(this)同步代码块

  2.当一个线程访问一个synchronized(this)

使用synchronized会发生死锁,死锁是程序中要避免的。死锁就是大家都想拿到对方的东西,但是却又不把自己的东西给出去造成的。

要避免死锁,就是要先释放自己的锁,或者尽量不同步方法,同步代码块的嵌套。

原文地址:https://www.cnblogs.com/shmilynanmei/p/8955937.html