并行与并发
并行:可以同时进行不同的任务
并发:交替的执行任务
高并发编程的意义、好处和注意事项
多线程:充分利用CPU的资源,加快相应的时间,可以使我们代码模块化、异步化、简单化
OS限制: Linux 1000个 windows 2000个
为什么要限制线程呢:需要分配栈空间
认识java里的线程
Java里的程序天生就是多线程的
几种新启线程的方式
Thread:对线程的抽象
Runnable: 对任务和业务逻辑的抽象
public class NewThread {
private static class UseThread extends Thread{
@Override
public void run() {
super.run();
System.out.println("I am extendec Thread");
}
}
public static class UseRunable implements Runnable {
@Override
public void run() {
System.out.println("I am extendec Runnable");
}
}
public static void main(String[] args)
throws InterruptedException, ExecutionException {
UseThread useThread=new UseThread();
useThread.start();
UseRunable useRunable=new UseRunable();
new Thread(useRunable).start();
}
}
关掉线程
stop() : 强制关掉线程,比较野蛮,不建议使用,可能会导致线程所占用的资源不会正常释放。
interrupt():对线程发起一个中断,给线程的一个中断标志位,不代表要立即停止工作,线程可以完全不理会。
isInterrupted():判定是否被中断
interrupted():boolean 静态方法,同样可以检测到中断标志位,但是被调用之后,会把isInterrupted()由true改成false.
private static class UseThread extends Thread{
@Override
public void run() {
super.run();
// System.out.println("I am extendec Thread");
String threadName=Thread.currentThread().getName();
System.out.println(threadName+"interrupt flag"+isInterrupted());
while (!Thread.interrupted()){
System.out.println(threadName+"is running");
System.out.println(threadName+"inner interrupt flag = "+isInterrupted());
}
System.out.println(threadName+"interrupt flag"+isInterrupted());
}
}
结果:
注意:
jdk里面线程是协作式,而不是抢占式
死锁状态,不会理会中断
线程常用方法和线程的状态
Start和Run方法
start只能调用一次,多次调用会抛出异常。
run可以当成一个普通的方法调用。
public class StartAndRun {
public static void main(String[] args) {
ThreadRun threadRun=new ThreadRun();
threadRun.setName("threadRun");
threadRun.run();
}
public static class ThreadRun extends Thread{
@Override
public void run() {
int i=10;
while (i>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I am "+Thread.currentThread().getName()+" and now the i="+i--);
}
}
}
}
可以看到调用run的是主线程而不是ThreadRun。
接下来用start方法试试。
public static void main(String[] args) {
ThreadRun threadRun=new ThreadRun();
threadRun.setName("threadRun");
threadRun.start();
}
可以看到调用的是线程本身。
以上就是start和run方法的最大区别。
了解yield()
yield(): 时间片到期,将线程从运行转为可运行状态。会让出当前cpu的执行权,但是让出的时间不可设定,并且此方法不会释放锁资源。
join():获取执行权,能让线程顺序的执行。可以在需要插队时使用。
线程的优先级
useThread.setPriority(10);
useThread.setPriority(1);
需要休眠或者IO操作的可以把优先级设置的高一些,偏重于计算的可以设置的低一些,确保计算机不会被这些计算把时间占据了…
非守护线程:通过New thread 等手动启动的线程。
守护线程:jdk自己内部或者通过参数配置启动的线程。
守护线程中finally不一定起作用。
synchronized关键字的使用方法
public class SynTest {
private long count=0;
private Object obj=new Object();
public long getCount(){
return count;
}
public void setCount(long count){
this.count=count;
}
//用在同步块上
public void incCount(){
synchronized (obj){
count++;
}
}
//用在方法上
public synchronized void incCount2(){
count++;
}
//count进行累加
public void incCount3(){
//this代表SynTest当前对象的实例
synchronized (this){
count++;
}
}
private static class Count extends Thread{
private SynTest simplOper;
public Count(SynTest simplOper){
this.simplOper=simplOper;
}
@Override
public void run(){
for(int i=0;i<10000;i++){
simplOper.incCount();
}
}
}
public static void main(String[] args) throws InterruptedException{
SynTest simplOper=new SynTest();
//启动两个线程
Count count1=new Count(simplOper);
Count count2=new Count(simplOper);
count1.start();
count2.start();
Thread.sleep(50);
System.out.println(simplOper.count);
}
}
对象锁:执行某段代码的时候要拿到对象上的锁才能进行,如果有两个对象,每个对象有自己的锁,意味着两个线程可以并行的进行。
类锁:在一个静态方法上面加了一个锁。在打了static方法上进行加锁的话,意味着加锁的是一个class对象,本质上还是对象锁。并不是一个真正存在的东西,和对象锁之间互不干扰。
注意:synchronized锁的是一个具体对象