欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

并发concurrent---1

程序员文章站 2022-03-28 22:03:26
背景:并发知识是一个程序员段位升级的体现,同样也是进入BAT的必经之路,有必要把并发知识重新梳理一遍。 说到并发concurrent,肯定首先想到了线程,创建线程有两种方法:1、从Java.lang.Thread类派生一个新的线程类,重载它的run()方法;2、实现Runnalbe接口,重载Runn ......

背景:并发知识是一个程序员段位升级的体现,同样也是进入bat的必经之路,有必要把并发知识重新梳理一遍。

 

说到并发concurrent,肯定首先想到了线程,创建线程有两种方法:1、从java.lang.thread类派生一个新的线程类,重载它的run()方法;2、实现runnalbe接口,重载runnalbe接口中的run()方法;建议使用方法二创建线程,因为,如果是通过扩展 thread类的方法来创建线程,那么这个自定义类就不能再去扩展其他的类,也就无法实现更加复杂的功能;而实现runnable接口的方法来定义该类为线程类,这样就可以避免java单继承所带来的局限性,也更符合面向对象编程的思想,最重要的就是使用实现runnable接口的方式创建的线程可以处理同一资源,从而实现资源的共享。

创建线程的两种方法:

 1 package www.concurent.test;
 2 public class traditionalthread {
 3 
 4     public static void main(string[] args) {
 5         //thread1:
 6         thread thread = new thread() {
 7             @override
 8             public void run() {
 9                 while(true) {
10                     try {
11                         thread.sleep(1000);
12                     } catch (interruptedexception e) {
13                         e.printstacktrace();
14                     }
15                     system.out.println("thread1: "+thread.currentthread().getname());
16                 }
17             }
18         }; 
19         thread.start();
20         
21         //thread2:
22         //runnable变量是线程要运行的代码的宿主,更适合面向对象思想的线程方法
23         thread thread2 = new thread(new runnable() {
24             @override
25             public void run() {
26                 while(true) {
27                     try {
28                         thread.sleep(1000);
29                     } catch (interruptedexception e) {
30                         e.printstacktrace();
31                     }
32                     system.out.println("thread2: "+thread.currentthread().getname());
33                 }
34             }
35         });
36         thread2.start();
37     }
38 }

线程和timer定时器很类似,下面介绍了两种和线程相似的定时器写法:1、定时一天之后调用方法查询天气情况接口,然后每隔60秒后继续调用该方法;2、定时每天00:39:32调用查询天气情况接口,通过hutool工具和timer定时器调用http天气状况接口的返回结果如下截图:(result2得到了天津的天气状况)

并发concurrent---1

通过hutool工具和timer定时器调用http天气状况接口

 1 import java.util.calendar;
 2 import java.util.date;
 3 import java.util.timer;
 4 import java.util.timertask;
 5 import cn.hutool.http.httputil;
 6 
 7 public class traditionaltimertest {
 8     //时间间隔
 9      private static final long period_day = 24 * 60 * 60 * 1000;
10     //timer 定时器
11     public static void main(string[] args) {
12         calendar cl = calendar.getinstance();
13         cl.set(calendar.hour_of_day, 0);
14         cl.set(calendar.minute, 39);
15         cl.set(calendar.second, 32);
16         date date = cl.gettime();
17         date datenow = new date();
18         //如果第一次执行定时任务的时间 小于 当前的时间
19         //此时要在 第一次执行定时任务的时间 加一天,以便此任务在下个时间点执行。如果不加一天,任务会立即执行。
20         if (date.before(datenow)) {
21             calendar cladd = calendar.getinstance();
22             cladd.settime(datenow);
23             cladd.add(calendar.day_of_month, 1);
24              date = cladd.gettime();
25         }
26         //timer1:
27         new timer().schedule(new timertask() {
28             @override
29             public void run() {
30                 system.out.println("hello");
31                 //hutool调用http接口
32                 string result1 = httputil.get("http://t.weather.sojson.com/api/weather/city/101030100");
33                 system.out.println("result1: "+result1);
34             }
35             //一天之后调用方法查询天气情况接口,然后每隔60秒后继续调用该方法
36         },period_day , 1000*60);
37         //timer2:
38         new timer().schedule(new timertask() {
39             @override
40             public void run() {
41                 //hutool调用http接口
42                 string result2 = httputil.get("http://t.weather.sojson.com/api/weather/city/101030100");
43                 system.out.println("result2: " + result2);
44             }
45             //定时每天00:39:32调用查询天气情况接口
46         }, date , period_day);
47     }
48 
49 }

 如果是单个线程调用都还ok,要是有多个线程同时调用那就会出现并发产生;比如有一个方法output()是经过charat(i)获取字符串i的字符并且打印再控制台,然后线程a和线程b同时调用output()方法,此时就会出现线程不安全问题(如银行取钱和转账同时进行),也就是并发;执行结果发现,线程a为执行完毕线程b就开始执行了,为了能后保证当有一个线程来执行某个方法时,其他的线程不能进来执行该方法,实现排他性,可以通过synchronized和reentrantlock来实现线程同步;二者其实区别不大,synchronized由于是底层jvm实现的互斥,因此效率会高一些,而reentrantlock的功能则比synchronized更多,比如定时获取某个锁,多个等待条件等,另外synchronized 会让线程阻塞,reentrantlock会让线程等待,但是从行为效果上来看是一样的;下面有个例子:并发结果如截图显示,理想状态是打印“huawei”或者“isoftstone”,但是由于并发打印出来诸如此类“ishuaweoftstoni”结果。

并发concurrent---1

fyi:

 1 import java.util.concurrent.locks.lock;
 2 import java.util.concurrent.locks.reentrantlock;
 3 
 4 public class mythreadsynchronized {
 5     public static void main(string[] args) {
 6         //要想调用内部类的对象,必须有外部类的实例对象
 7         new mythreadsynchronized().init();   // 外部类的实例对象
 8     }
 9     public void init() {
10         final outputer outputer = new outputer();
11         //thread1:
12         new thread(new runnable() {
13             @override
14             public void run() {
15                 while(!false) {
16                     try {
17                         thread.sleep(100);
18                     } catch (interruptedexception e) {
19                         e.printstacktrace();
20                     }
21                     outputer.output3("huawei");
22                 }
23             }
24         }).start();
25         
26         //thread2:
27         new thread(new runnable() {
28             @override
29             public void run() {
30                 while(!false) {
31                     try {
32                         thread.sleep(100);
33                     } catch (interruptedexception e) {
34                         e.printstacktrace();
35                     }
36                     outputer.output("isoftstone");
37                 }
38             }
39         }).start();
40     }
41     //当有一个线程来执行某个方法时,其他的线程不能进来执行该方法,排他性、独一无二;
42     //使用synchronized/lock同步,且线程用的同步锁是同一个同步对象,可用this互斥或方法.class
43     //synchronized由于是底层jvm实现的互斥,因此效率会高一些
44     //reentrantlock的功能则比synchronized更多,比如定时获取某个锁,多个等待条件
45     //synchronized 会让线程阻塞,reentrantlock会让线程等待,但是从行为效果上来看是一样的;
46 class outputer{
47     //内部类  静态方法中不能new内部类的实例对象
48         //synchronized:
49         public synchronized void output(string name) {
50             for(int i = 0; i<name.length(); i++) {
51                 system.out.print(name.charat(i));
52             }
53             system.out.println();// switch line
54         }
55         
56         //线程不安全
57         public  void output3(string name) {
58             for(int i = 0; i<name.length(); i++) {
59                 system.out.print(name.charat(i));
60             }
61             system.out.println();// switch line
62         }
63         
64         //lock:
65         public void ouputlock(string name) {
66             lock lock = new reentrantlock();
67             lock.lock();   // 上锁同步
68             try {
69                 for (int i = 0; i < name.length(); i++) {
70                     system.out.print(name.charat(i));
71                 }
72                 system.out.println();// switch line
73             } finally {
74                 lock.unlock();  // 解锁
75             }
76         }
77         
78 }
79     
80 }