在劫

吾生也有涯,而知也无涯 。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

进程与线程的区别:

进程
正在运行的程序,是系统进行资源分配和调用的独立单位
每一个进程都有它自己的内存空间和系统资源
线程
进程中的单个顺序控制流,是一条执行路径
一个进程如果只有一条执行路径,则是单线程程序
一个进程内有多条执行路径,则是多线程程序
一个进程内可以执行多个任务,每个任务就是一个线程

多线程的意义
单进程计算机只能做一件事,现在计算机同一时间段内可以执行多个任务,提高CPU的利用率
多线程的意义
多线程的存在,不是提高程序的执行速度,其实是为了提高应用程序的使用率
程序执行是抢占CPU的资源,CPU的执行权
多个进程抢这些资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到
无法保证线程在什么时候抢到资源,线程执行有随机性

并发:逻辑上同时发生,指在某个时间内同时运行多个程序。
并行:物理上同时发生,指在某个时间点运行多个程序。、
Java程序运行原理
    java命令启动java虚拟机,启动JVM,等于启动一个应用程序,也就是启动一个进程。
    该进程会自动启动一个主线程,然后主线程去调用某个类的main方法,所以main方法运行在主线程中,
    再次之前程序都是单线程的。
    JVM是多线程,垃圾回收线程也要先东西,否则会很容易出现内存溢出。
    最少启动了主线程和垃圾回收线程两个线程。

线程是依赖进程存在的,所以要先调用一个进程。进程由系统创建的,所以我们应该调用系统功能创建一个进程。
Java是不能调用系统功能的,所以我们没有办法直接实现多线程。Java可以调用C/C++写好的程序实现多线程,由C/C++调用系统功能创建进程,然后由Java去调用这样的东西,然后提供一些类供我们使用,就可以实现多线程程序。
实现多线程的方式

  1. 继承Thread
public class ThreadJava extends Thread {
	//重写run()方法
	public void run() {

	}
}
  1. 实现Runnable接口
public class RunnableJava Implements Runnable{
	//重写run()方法
	public void run(){

	}
}

执行多线程
如果是执行调用run()方法的话就会作为普通类执行,而不是多线程进行执行。

//继承Thread类的执行方式
	ThreadJava tj = new ThreadJava();
	tj.start()

//实现Runnable接口的执行方式
	RunnableJava rj = new RunnableJava();
	Thread t = new Thread(rj);
	t.start();

Thread

/*
 * 两个线程分别得到i的值,分别执行run()方法体
 * */
public class newTest extends Thread{
	private int i = 100;
	public void run() {
		while (true) {
			if (i > 0) {
				System.out.println("i的值为: " + (i--) + "--------" + Thread.currentThread().getName());
			}
		}
	}
	public static void main(String[] srgs) {
		newTest nt = new newTest();
		newTest nt2 = new newTest();
		nt.start();
		nt2.start();
	}
}
/*
 * 两个线程共用i
 * */
public class newTest extends Thread{
	private static int i = 100;
	public void run() {
		while (true) {
			if (i > 0) {
				System.out.println("i的值为: " + (i--) + "--------" + Thread.currentThread().getName());
			}
		}
	}
	public static void main(String[] srgs) {
		newTest nt = new newTest();
		newTest nt2 = new newTest();
		nt.start();
		nt2.start();
	}
}

这里主要看i是类变量还是成员变量,类变量任意类对象都可以对它进行更改,成员变量因为对象的不同而不同。
实现Runnable接口
程序一:下面程序每次输出i的值减一

public class RunnableJava implements Runnable{
     private int i = 100;
     private Object obj = new Object();
     public void run() {
           while (true) {
                synchronized (obj) {
                      obj.notifyAll();
                      if (i > 0) {
                           System.out.println("i的值为: " + (i--) + "--------" + Thread.currentThread().getName());
                      }
                      try {
                           Thread.sleep(1000);
                      } catch (InterruptedException e) {
                           // TODO Auto-generated catch block
                           e.printStackTrace();
                      }
                      try {
                           obj.wait(1000);
                      } catch (InterruptedException e) {
                           // TODO Auto-generated catch block
                           e.printStackTrace();
                      }
                }
           }
     }
}
//---------------------------------------------------------------------------------------------------------------------------------
           RunnableJava rj1 = new RunnableJava();
           Thread t1 = new Thread(rj1, "线程rj1 ---------- 线程一");
           Thread t2 = new Thread(rj1, "线程rj1 ---------- 线程二");
           Thread t3 = new Thread(rj1, "线程rj1 ---------- 线程三");
           t1.start();
           t2.start();
           t3.start();

程序二:如果建两个Runnable的实现类对象分别传入多个Thread中,如果想让两个Runnable分别计算输出i的值,i不能用static修饰,锁对象可用static修饰,也可以不用。不过这里是有区别的,不用static代表分别传入到Thread的Runnable的两个内存每次只能有一个Thread访问,使用static的话同一只能有一个线程访问两个Runnable内存中的一块,也就是只能执行一个Runnable的run()方法

public class RunnableJava implements Runnable{     
	private int i = 100;    
	private static Object obj = new Object();   
	public void run() {         
		while (true) {                
			synchronized (obj) {                    
				obj.notifyAll();                   
				if (i > 0) {                         
					System.out.println("i的值为: " + (i--) + "--------" + Thread.currentThread().getName());          
					}                     
				try {                          
					Thread.sleep(1000);                      
					} catch (InterruptedException e) {                          
					// TODO Auto-generated catch block                          
						e.printStackTrace();                    
						}                    
				try {                          
					obj.wait(1000);                
					} catch (InterruptedException e) {                          
						e.printStackTrace();                     
					}             
				}         
			}  
		}
	}

 
public class RunnableJava implements Runnable{
     private int i = 100;
     private Object obj = new Object();
     public void run() {
           while (true) {
                synchronized (obj) {
                      obj.notifyAll();
                      if (i > 0) {
                           System.out.println("i的值为: " + (i--) + "--------" + Thread.currentThread().getName());
                      }
                      try {
                           Thread.sleep(1000);
                      } catch (InterruptedException e) {
                           // TODO Auto-generated catch block
                           e.printStackTrace();
                      }
                      try {
                           obj.wait(1000);
                      } catch (InterruptedException e) {
                           // TODO Auto-generated catch block
                           e.printStackTrace();
                      }
                }
           }
     }
}

           RunnableJava rj1 = new RunnableJava();
           RunnableJava rj2 = new RunnableJava();
           Thread t1 = new Thread(rj1, "线程rj1 ---------- 线程一");
           Thread t2 = new Thread(rj1, "线程rj1 ---------- 线程二");
           Thread t3 = new Thread(rj1, "线程rj1 ---------- 线程三");
           t1.start();
           t2.start();
           t3.start();
           Thread t4 = new Thread(rj2, "线程rj2 ---------- 线程四");
           Thread t5 = new Thread(rj2, "线程rj2 ---------- 线程五");
           Thread t6 = new Thread(rj2, "线程rj2 ---------- 线程六");
           t4.start();
           t5.start();
           t6.start();

程序三:如果建两个Runnable的实现类对象分别传入多个Thread中,如果想让两个Runnable共同计算输出j的值,i不和锁对象必须用static修饰

public class RunnableJava implements Runnable{
     private static int i = 100;
     private static Object obj = new Object();
     public void run() {
           while (true) {
                synchronized (obj) {
                      obj.notifyAll();
                      if (i > 0) {
                           System.out.println("i的值为: " + (i--) + "--------" + Thread.currentThread().getName());
                      }
                      try {
                           Thread.sleep(1000);
                      } catch (InterruptedException e) {
                           // TODO Auto-generated catch block
                           e.printStackTrace();
                      }
                      try {
                           obj.wait(1000);
                      } catch (InterruptedException e) {
                           // TODO Auto-generated catch block
                           e.printStackTrace();
                      }
                }
           }
     }
}

这里要是静态变量的知识,static修饰的变量是属于类的,不管你new几个对象,都只会有这一个对象。所以
程序一,只有一个Runnable对象传入Thread,访问的是这个Runnable对象的内存,这里只有一个i和锁对象,所以不需要使用static修饰;
程序二,有两个Runnable对象分别传入Thread,这里有两块内存,要分别计算输出i 的值,i就必须每个对象给一个,但是锁对象可以是唯一的,也可以不是唯一的。锁对象static修饰代表同一时间只能有一个run()方法执行操作,不用static修饰代表同一时间段传入两个Runnable对象的两个线程可以同时被执行;
程序三,i的值和锁对象都使用static修饰,代表不管有几个Runnable对象传入多少个Thread中,变量i从100递减到1只会执行一次,和程序一结果相同。
上面就是看内存是否访问的是同一个变量,使用的锁对象是否是同一个对象,锁住之后的方法块每次都只能一个得到锁对象的线程可以执行。
线程同步synchronized
通过synchronized关键字实现线程同步,synchronized是不被继承的
1、synchronized同步代码块,同步代码块传入的锁对象可以是任意对象

//线程必须得到锁才能执行同步代码块,否则无法执行同步代码块
public class SynchronizedTest2 implements Runnable {
	private static int i = 0;
	private static int j = 100;
	//锁对象不能为空值,定义为类变量则为所有类对象共用
	private static Object obj1 = new Object();
	private static Object obj2 = new Object();

	@Override
	public void run() {
		while(true) {
			synchronized (obj1) {
				if(i < 100) {
					System.out.println(Thread.currentThread().getName() + "---------" + (i++));
				}
			}
			
			synchronized (obj2) {
				if(j > 0) {
					System.out.println(Thread.currentThread().getName() + "---------" + (j--));
				}
			}
		}
		
	}

}

2、synchronized修饰成员方法,修饰成员方法是锁对象问对象本身,也就是this

/*
 * synchronized修饰普通方法对象锁是本身,即this
 * */
public class SynchronizedMethod2 implements Runnable{

	public synchronized void method() {
		System.out.println("synchronized修饰普通方法" + Thread.currentThread().getName());
	}
	
	public void run() {
		// TODO Auto-generated method stub
		while(true) {
			this.method();
			synchronized(this) {
				System.out.println("synchronized修饰同步代码块" + Thread.currentThread().getName());
			}
		}
	}
	
	public static void main(String[] args) {
		SynchronizedMethod2 sm = new SynchronizedMethod2();
		Thread t1 = new Thread(sm, "线程一");
		SynchronizedMethod2 sm2 = new SynchronizedMethod2();
		//传入sm2的时候锁是this sm2
		//传入sm的时候锁是this  sm
		//Thread t2 = new Thread(sm2, "线程二");
		Thread t2 = new Thread(sm, "线程二");
		t1.start();
		t2.start();
	}
}

3、synchronized修饰静态方法,修饰静态方法的锁对象是类本身的.class文件

/* synchronized(类.class)锁住的是整个类
 * synchronized修饰静态方法和同步代码块,在两个方法体中都sleep()使得其他线程有机会得到执行
 * 不管创建了多少个Runnable对象传入到不同的Thread中,每次只能有一个Thread执行synchronized(类.class)代码块,同synchronized修饰的静态方法
 * */
public class SynchronizedMethod implements Runnable {
	private static int i = 20;
	private int j = 0;
	private static Object obj = new Object();
	public synchronized static void method1() {
		//SynchronizedMethod.class.notifyAll();
		System.out.println("synchronized修饰静态方法:" + "---" + Thread.currentThread().getName());
		if (i > 0) {
			System.out.println("静态方法中i的值: " + (i--) + "---" + Thread.currentThread().getName());

			System.out.println("静态方法执行完");
//			try {
//				Thread.sleep(1000);
//			} catch (InterruptedException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//			try {
//				SynchronizedMethod.class.wait();
//			} catch (InterruptedException e1) {
//				// TODO Auto-generated catch block
//				e1.printStackTrace();
//			}
		}
	}

	public void run() {
		// 方法的调用放在while()循环外只会执行method1()方法
		// method1();
		while (true) {
			method1();
			//同步代码块锁对象为类的class文件,则是锁住整个类的,其他线程必须等代码块执行完释放锁才能继续执行
			synchronized (SynchronizedMethod.class) {
			//把同步代码块锁对象换成obj,线程之间互无关系,可以任意执行自己对象的锁
			//synchronized (obj) {
				//SynchronizedMethod.class.notifyAll();
				System.out.println("synchronized使用类class文件修饰同步代码块" + "---" + Thread.currentThread().getName());
				if (j < 20) {
					System.out.println("同步代码块中j的值: " + (j++) + "---" + Thread.currentThread().getName());
					System.out.println("同步代码块执行完");
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
//					try {
//						SynchronizedMethod.class.wait();
//					} catch (InterruptedException e1) {
//						// TODO Auto-generated catch block
//						e1.printStackTrace();
//					}
				}
			}
		}
	}

}

4、synchronized修饰run()方法,代表某个线程只能有一个run()方法执行

public class SynchronizedRun implements Runnable{

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SynchronizedRun sr = new SynchronizedRun();
		Thread t1 = new Thread(sr, "线程一");
		//SynchronizedRun sr2 = new SynchronizedRun();
		Thread t2 = new Thread(sr, "线程二");
		t1.start();
		t2.start();
	}

	//等于synchronized(this),可以保证一个线程只能有一个run()方法在运行
	//synchronized(this)在没有释放锁的情况下只有一个线程能够执行这个方法
	public synchronized void run() {
		// TODO Auto-generated method stub
		System.out.println("多线程run方法" + Thread.currentThread().getName());
	}

}

synchronized锁住的是括号里的对象,而不是代码。对于非static的synchronized方法,锁的就是对象本身也就是this。就上面程序二的类,创建两个Runnable对象,分别传入到Thread中,每一个Runnable对象的同步代码块有一个锁对象obj,两个Runnable对象传到的Thread多线程可以同时执行同步代码块中的代码。而同一个Runnable对象下的多线程之间互斥,谁得到锁谁执行。所以synchronized锁住的是对象不是代码块。
static synchronized方法,static方法可以直接类名加方法名调用,方法中无法使用this,所以它锁的不是this,而是类的Class对象,所以,static synchronized方法也相当于全局锁,相当于锁住了整个代码段。同步代码块如果想要全局锁可以传入类本身的class文件。
线程同步Lock
1、lock方法,没有获取锁一直等待

public class LockJava implements Runnable {
	private static int i = 100;
	private static Lock lock = new ReentrantLock();
//	private static Condition c = lock.newCondition();

	public void run() {
		while(true) {
			lock.lock();
			try {
//				c.signalAll();
				if(i > 0) {
					System.out.println(Thread.currentThread().getName() + "----" + (i--));
//					try {
//						c.await();
//					} catch (InterruptedException e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//					}
				}
			}finally {
				lock.unlock();
			}
		}
	}
}

2、tryLock()方法
tryLock()方法返回一个boolean值,判断是否可以获取锁,并立即返回结果。所以tryLock()和lock()方法一样使用的话如果没有获取锁只会返回false,但是在unLock()的时候会报错,因为并没有获取锁。不过报错的情况并不是使程序终止

/*
 * IllegalMonitorStateException异常
 * 线程一运行获得lock1,等待,
 * 线程二运行获得lock2,等待,
 * 线程一执行lock2锁锁住的部分,并不能获取锁,
 * */
public class DeathLock1 {
	static Lock lock1 = new ReentrantLock();
	static Lock lock2 = new ReentrantLock();
	public static void main(String[] args) {
		new Thread(new Runnable() {
			public void run() {
				while(true) {
					System.out.println(Thread.currentThread().getName() + "开始运行:");
					lock1.lock();
					try {
						System.out.println(Thread.currentThread().getName() + "get  lock1");
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						//lock2.lock();
						//这里并没有获得锁
						lock2.tryLock();
						try {
							System.out.println(Thread.currentThread().getName() + "get lock2");
						}finally {
							//这里会报IllegalMonitorStateException错误
							//因为此时锁不在这里
							lock2.unlock();
						}		
					}finally {
						lock1.unlock();
					}
				}			
			}			
		}, "线程一").start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(true) {
					System.out.println(Thread.currentThread().getName() + "开始运行:");
					lock2.lock();
					try {
						System.out.println(Thread.currentThread().getName() + "get  lock2");
						
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						//lock1.lock();
						lock1.tryLock();
						try {
							//boolean booleanlock1 = lock1.tryLock();
							System.out.println(Thread.currentThread().getName() + "get lock1");
						}finally {
							//没有获取锁,会报错
							lock1.unlock();
						}	
					}finally {
						System.out.println("线程二释放lock2");
						lock2.unlock();
					}
				}			
			}
				
			
			
		}, "线程二").start();
		
	}
}

可以使用if语句,tryLock()作为条件,获取了就执行,不获取就不执行

public class DeathLock1 {
	static Lock lock1 = new ReentrantLock();
	static Lock lock2 = new ReentrantLock();
	static Condition  c1 = lock1.newCondition();
	static Condition  c2 = lock2.newCondition();
	public static void main(String[] args) {

		new Thread(new Runnable() {
			public void run() {
				while (true) {
					System.out.println(Thread.currentThread().getName() + "开始运行:");
					lock1.lock();
					try {
						System.out.println(Thread.currentThread().getName() + "get  lock1");
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						//线程二释放了lock2,这里就可以获取
						if (lock2.tryLock()) {
							try {
								System.out.println(Thread.currentThread().getName() + "get lock2");
								try {
									Thread.sleep(1000);
								} catch (InterruptedException e) {
									e.printStackTrace();
								}
							} finally {
								lock2.unlock();
							}
						}
					} finally {
						System.out.println("线程一释放了lock1");
						lock1.unlock();
					}
				}
			}
		}, "线程一").start();

		new Thread(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
					System.out.println(Thread.currentThread().getName() + "开始运行:");
					lock2.lock();
					try {
						System.out.println(Thread.currentThread().getName() + "get  lock2");
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					} finally {
						System.out.println("线程二释放了lock2");
						lock2.unlock();
					}
			}

		}, "线程二").start();

	}
}

tryLock()不是lock()那种使用方式

lock.tryLock() //这里返回的是boolean,这里不会报错
...
lock.unlock() //这里没有获取锁的话会报错

3.lockInterruptibly,没有当前线程没有被中断,则获取锁
允许在等待时由其它线程调用等待线程的Thread.interrupt方法来中断等待线程的等待而直接返回,这时不用获取锁,而会抛出一个InterruptedException。而ReentrantLock.lock方法不允许Thread.interrupt中断,即使检测到Thread.isInterrupted,一样会继续尝试获取锁,失败则继续休眠。只是在最后获取锁成功后再把当前线程置为interrupted状态。
线程同步读写锁

public class LockWriterReaderJava {
	private static int i = 0;
	private static ReentrantReadWriteLock  lock = new ReentrantReadWriteLock();
	private static ReentrantReadWriteLock.ReadLock  read = lock.readLock();
	private static ReentrantReadWriteLock.WriteLock write = lock.writeLock();
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//读,可以随意访问
		new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(true) {
					write.lock();
					try {
						if(i < 100) {
							System.out.println(Thread.currentThread().getName() + (i++) + "----i增加1");
						}
					}finally {
						write.unlock();
					}
					read.lock();
					try {
						if(i < 100) {
							System.out.println(Thread.currentThread().getName() + i);
						}
					}finally {
						read.unlock();
					}
				}
			}
			
		}, "线程一").start();
		
		//写,每次只能一个线程进行访问
		new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(true) {
					read.lock();
					try {
						if(i < 100) {
							System.out.println(Thread.currentThread().getName() + i);
						}
					}finally {
						read.unlock();
					}
				}
			}
			
		}, "线程二").start();
		
	}

}

写锁可以“降级”为读锁;读锁不能“升级”为写锁。在线程持有读锁的情况下,该线程不能取得写锁(因为获取写锁的时候,如果发现当前的读锁被占用,就马上获取失败,不管读锁是不是被当前线程持有)在线程持有写锁的情况下,该线程可以继续获取读锁(获取读锁时如果发现写锁被占用,只有写锁没有被当前线程占用的情况才会获取失败)。
死锁

/*
	 * 线程一开始运行: 线程一get到obj1 线程二开始运行: 线程二get到obj2
	 * 
	 * 线程一运行获得obj1,到sleep()方法,这个时候 线程二运行获得obj2,到sleep()方法
	 * 此时线程一等待线程二释放obj2锁继续运行,线程二等到obj1继续运行,都没等到,所以死锁。
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				while (true) {
					System.out.println(Thread.currentThread().getName() + "开始运行:");
					synchronized (obj1) {
						System.out.println(Thread.currentThread().getName() + "get到obj1");
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						synchronized (obj2) {
							System.out.println(Thread.currentThread().getName() + "get到obj2");
							try {
								Thread.sleep(1000);
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					}
				}
			}

		}, "线程一").start();

		new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				while (true) {
					System.out.println(Thread.currentThread().getName() + "开始运行:");
					synchronized (obj2) {
						System.out.println(Thread.currentThread().getName() + "get到obj2");
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						synchronized (obj1) {
							System.out.println(Thread.currentThread().getName() + "get到obj1");
							try {
								Thread.sleep(1000);
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					}
				}
			}

		}, "线程二").start();
	}
}

线程调度
线程状态:

posted on 2018-07-14 16:41  长嘴大耳怪  阅读(172)  评论(0编辑  收藏  举报