进程和线程

进程:

jps ps-ef能看见的,就是进程。

程序启动之后,这个程序就是进程;但是有些程序会启动多个进程(像nginx)。

Jvm会为进程在内存中分配一个独立的运行空间

 

线程:

程序内部的一个独立的空间;在进程内部,再划分一些独立的空间。线程有自己的内存空间,就是有栈(存储局部变量,操作数)。线程在工作的时候本质就是调一些方法,我这个线程和另一个线程调用同一份代码,方法的代码只有一份,线程有两个实例在工作,这两个线程中的局部变量是不相同,在内存里面划分两片独立的空间,各自存自己的局部变量,但是两个线程运行的逻辑是同一份代码。QQ同时跟很多人聊天,就是很多的线程。图形化界面的程序,线程很多,类似word之类的。

传统Web服务,来一个用户请求,就开一个线程去响应他。线程的事情一般丢给Tomcat去做。

 

 

多线程:

就是在一个进程里面开启多个线程,让多个线程同时去完成某些任务。比如后台服务系统,就可以用多个线程同时响应多个客户请求。

 

为什么多个线程可以同时运行:

其实根本不可能同时运行,最多有cpu个同时运行,只是cpu切换很快而已。Cpu在线程之间切换。

Java实现线程的两种方法:

继承Thread;实现runnable()方法

public class MyThreadExtends extends Thread{
	String flag;	
	public MyThreadExtends(String flag){
		this.flag = flag;
	}	
	public void run(){
		String tname = Thread.currentThread().getName();
		System.out.println(tname + "线程run方法被调用了");
		Random random = new Random();
		for(int i = 0; i<20; i++){
			try {
				Thread.sleep(random.nextInt(10)*100);//sleep里面是毫秒
				System.out.println(tname+ "...."+ flag);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}		
		}
	}
	public static void main(String[] args) {		
		Thread thread1 = new MyThreadExtends("a");
		Thread thread2 = new MyThreadExtends("b");		
//		thread1.start();
//		thread2.start();		
		
//		thread1.run();
//		thread2.run();
		
		//两种的区别,
		//run()这个是简单的调用,工作实在主线程中,主线程就				 
		//在一个独立空间,变量什么的都在一个空间中。
        //而start(),开启新的空间,在这个新的空间有自己的局部变量的一些
		//存储的地方,有自己的程序计数器,独立的去运行。 
	}

}

public class MyThreadImpl implements Runnable{
	int x;
	public MyThreadImpl(int x){
		this.x = x;
	}
	
	public void run() {
		String tname = Thread.currentThread().getName();
		System.out.println(tname + "线程run方法被调用了");
		Random random = new Random();
		for(int i = 0; i<20; i++){
			try {
				Thread.sleep(random.nextInt(10)*100);//sleep里面是毫秒
				System.out.println(tname+ "...."+ x);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
		}		
	}
	
	public static void main(String[] args) {
		Thread thread1 = new Thread(new MyThreadImpl(1),"thread1");//new Thread 然后传一个runnable的实现
		Thread thread2 = new Thread(new MyThreadImpl(2),"thread2");

//		thread1.start();
//		thread2.start();		
		
//		thread1.run();
//		thread2.run();
	}
}

同步锁synchronized:  

java的关键字)同样的代码块,不通的线程,只能有一个线程执行。解决共享数据冲突

伪代码:

synchronized( 需要任意一个对象()    )

{

 代码块中放操作共享数据的代码;

}

缺陷:

1)同步代码块里面,发生异常,jvm会释放这个锁,让其他线程享有。

2)获取锁的线程执行完代码块,然后才释放对锁的占有

3)降低效率,会等待很长时间


Lock

(是类)可以不让等待的线程一直无期限的等待下去。比较:Synchronized 不需要用户手动释放锁,当 synchronized代码块执行完后,系统会自动释放对锁的占用。 Lock需要用户去手动释放锁。

lock接口中的方法:

Public interface Lock{
   void lock();
   void lockInterruptibly() throw InterruptedException;//等待的人可以中断,就是说可以不用等了,可以去做其他事情了
   boolean trylock();//尝试获取锁,可以不用等待,可以做一些异步的功能
   boolean trylock(long Time,TimeUnit unit) throw InterruptedException;//尝试过程可以设置等待时间
   void unlock();
}

读写锁(ReadWriteLock):

读操作是可以并行读的;然而写操作才可能产生冲突,我写的时候,你就不能读了,你也就更不能写了。如果大家都拿到的是读的锁,那大家可以同时进行都操作,但是如果其中有一个人拿到了写操作的时候,其他人就不能读也不能写。

ReadWriteLock接口中的方法:

Public interface ReadWriteLock{
  Lock readLock();
  Lock writeLock();
}


Locksynchronized选择:

1、Lock是接口,而synchronized是关键字,synchronized是内置的语言实现

2、Synchronized在发生异常的时候,会自动释放锁,所以不会产生死锁的现象。而Lock发生异常的时候,如果没有主动unlock释放锁,就会造成死锁现象,因此使用lock的时候,一定要在finally里面进行unlock

3、Lock可以让等待的线程中断,而synchronized却不行,使用synchronized时,等待线程会一直等待下去,不能响应中断。

4、通过Lock可以知道有没有获取锁,但是synchronized不行。

5、Lock可以提高多线程进行读操作效率。

在性能上来说,如果竞争不激烈的时候,两则性能差不多,但是竞争激烈的时候,此时lock优于synchronized

上述总结:

实际生产环境中,不会new Thread().start();   来一个客户端就产生一个线程,当请求量大的时候,超过了系统内存承受能力时候,并且线程多了, cpu 需要在线程之间做轮询,也损耗资源,影响机器的性能和稳定性。所以就有了线程池。

线程池:

一定线程数量,根据需要改变run方法进行不通逻辑的实现。线程池可以做成固定大小的,也可以做成弹性伸缩的。线程池实质就是一个数组或者时Array或者LinkList,把线程事先new好放进去。


线程池的经验之谈:

线程池在单机版的时候有用,在分布式的时候就不管用了,比如:抢购系统,需要高的响应速度,但是操作数据库库存又是很慢的操作,所以当用户请求的时候,会等很久得不到反应。所以此时可以这么做,把用户的请求丢到队列里面,相当于放到内存里面,然后返回一个等待页面给用户,这里实现了异步解耦,用户收到等待消息,然后服务器就自己去从队列里面取出请求,然后进行处理。这样看起来好像可以,但是一个公司抢购的业务往往不止一个,可能有10多个,20多个,甚至更多,并且都是几千万几千万的并发,那就会导致内存爆炸,这个时候就需要开启另外一台服务器,专门做消息队列的(JMS)。


线程池在java.util.concurrent包里面。

在这个包里面,有5中线程池创建方式:

1Single Thread Executor:只有一个线程的线程池

 代码:Executors.newSingleThreadExecutor()

2Cached Thread Pool:线程池里面有很多线程看同时执行的,老的线程会被新的任务触发重新执行,如果有一个线程超过60秒没有任务执行,那么将终止并从线程池中删除。

 代码:Executors.newCacheThreadPool()

3Fixed Thread Pool:固定数量的线程池,如果没有新任务,那么线程会一直等

 代码:Executors.newFixedThreadPool(int size)

 线程数量根cpu保持一致,跟任务类型有关(io密集型还是运算密集型),运算密集型,就设小一点。io密集型设置大一点,因为里面涉及到硬件底层的中断,阻塞,通知,cpu相对快,所以开多点线程,但是硬盘速度也是有限的,开再多的线程速度也是有限的,所以这时相对的。

 Cpu数量获得: int CpuNums = RunTime.getRunTime().availableProcessors();

4Scheduled Thread Pool:就是有世家规定,例如:把任务丢进去,我不让你马上执行,隔五分钟在执行或者每两分钟执行一次。

 代码:Executors.newScheduledThreadPool()

5Single Thread Scheduled Pool:只有一个线程

 代码:Executors.newSingleThreadScheduledExecutor()


synchronizednotifywait的一些知识

伪代码:
Public void run(){
   Synchronized(需要被锁的对象obj){
      Obj.notify();//唤醒其他也在等待obj资源的线程,把obj交给这个线程,但是本线程并没有阻塞,而是继续执行
      Obj.wait();//该线程释放cpu控制,释放obj的锁,该线程阻塞,等待被唤醒,那么此时另一个线程获得锁,继续执行
   }
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值