package com.qyl.springboot.controller;
// 1.创建一个子类类继承Thread
class MyThread extends Thread{
//2.在子类中重写Thread的run()方法 线程要做的事写到run()方法中
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
System.out.println(i+"---"+Thread.currentThread().getName());
}
}
}
};
public class ThreadTest {
public static void main(String[] args) {
// 3.创建该子类的对象
//主线程执行
MyThread myThread = new MyThread();
MyThread myThread1 = new MyThread();
//4.通过此对象调用start方法
//创建出来的线程执行
myThread.start();
myThread1.start();//乡启动多个就多创建对象即可
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
System.out.println(i+ " ++++++++++++++-"+Thread.currentThread().getName());
}
}
//这种方法也可以 匿名子类
System.out.println("/");
new Thread(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 != 0){
System.out.println(Thread.currentThread().getName()+""+ i );
}
}
}
}.start();
}
}
输出结果:
48---Thread-0 78---Thread-1 50---Thread-0 18 ++++++++++++++-main 52---Thread-0 80---Thread-1 82---Thread-1 84---Thread-12. 多线程创建方式2
实现Runnable接口
1.创建一个实现了Run那边了接口的类
2.实现类去实现Runable中的抽象方法
3.创建实现类的对象
4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
5.通过Thread类的对象调用start()方法
package com.qyl.springboot.controller;
//1.创建一个实现了Run那边了接口的类
class MyRunnable implements Runnable{
//2.实现类去实现Runable中的抽象方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
System.out.println(""+i+ " ++++++++++++++-"+Thread.currentThread().getName());
}
}
}
}
public class RunableTest {
public static void main(String[] args) {
//3.创建实现类的对象
MyRunnable m1 = new MyRunnable();
//4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread thread = new Thread(m1);
thread.setName("liudeh");
thread.start();
Thread t2 = new Thread(m1);
t2.setName("liudsssssssssseh");
t2.start();
}
}
2.线程生命周期
- 创建 调用start()就绪 sleep()时间到,join()结束,获取同步锁,notify()/notifyALL(),resume()阻塞 失去cpu执行权,或者yield()运行 sleep(),join(),等待同步锁,wait(),suspend()死亡 执行完run(),调用stop(),出现Error/Exception且没处理
/**
* 线程同步与安全
* 处理共享数据的时候会出现线程安全问题
* 加锁解决
* 4.在java中,通过同步机制来解决线程安全问题
* 方式一 : 同步代码块
* synchronized (同步监视器) {
* //需要被同步的代码 (吃操作共享数据的代码就是需要被同步的代码)
* }
* 说明: 1.(吃操作共享数据的代码就是需要被同步的代码)
* 2.同步监视器就是 锁 任何类的对象都能充当锁
* 锁的要求 : 多个线程供用同一把锁
* 哪怕你用一个狗 dag对象都可以
* 方式二 : 同步方法
*
*
* 5.同步的方式虽然解决了线程安全
* 缺点是同步代码块里面是单线程
*/
package com.qyl.java;
class Window implements Runnable{
private int titck = 100;
Object object = new Object();
@Override
public void run() {
while (true){
//同步代码块
synchronized(object){
if (titck>0){
System.out.println(Thread.currentThread().getName()+" 卖票-----票号码为: " + titck );
titck--;
}else {
break;
}
}
}
}
}
public class SyncThread {
public static void main(String[] args) {
Window m1 = new Window();
Thread t1 = new Thread(m1);
Thread t2 = new Thread(m1);
Thread t3 = new Thread(m1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
注意:implement Runnable 的时候 this(当前对象 ) 就可以当做锁 extends Threads的时候 不行
2.同步方法// 1.一种情况可以直接把run改为同步的,但是要注意场景
class Window implements Runnable{
private int titck = 100;
Object object = new Object();
@Override
public synchronized void run() {
while (true){
//同步代码块
synchronized(this){
if (titck>0){
System.out.println(Thread.currentThread().getName()+" 卖票-----票号码为: " + titck );
titck--;
}else {
break;
}
}
}
}
}
1.同步方法解决Runnable
package com.qyl.java;
class Window implements Runnable{
private int titck = 100;
Object object = new Object();
@Override
public void run() {
while (true){
sync();
}
}
private synchronized void sync (){ //同步监视器就是this
//同步代码块
if (titck>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 卖票-----票号码为: " + titck );
titck--;
}
}
}
public class SyncThread {
public static void main(String[] args) {
Window m1 = new Window();
Thread t1 = new Thread(m1);
Thread t2 = new Thread(m1);
Thread t3 = new Thread(m1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
2.同步方法解决thread
package com.qyl.java;
class Windows extends Thread {
private static int tickets = 100;
private static Object object = new Object();
@Override
public void run() {
while (true) {
//同步代码块
show();
}
}
private static synchronized void show(){ //加个static 就可以了
if (tickets > 0) {
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 卖票-----票号码为: " + tickets);
tickets--;
}
}
}
public class extendsThread {
public static void main(String[] args) {
Windows w1 = new Windows();
Windows w2 = new Windows();
Windows w3 = new Windows();
w1.setName("窗口1");
w2.setName("窗口2");
w3.setName("窗口3");
w1.start();
w2.start();
w3.start();
}
}
4.Thread 的常用方法介绍:
1) start():
启动当前线程,调用当前线程的run()方法 。
2) run():通常是重写Thread 的run()方法 将线程要做的事情声明在该方法中
3) currentThread() :Thread 的静态方法 获取到当前线程
4)getName() setName():给线程名字的方法
package com.qyl.springboot.controller;class MyThread1 extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { if(i % 2 == 0 ){ try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Thread.currentThread().setName("lalala"); 线程命名 方式1 System.out.println(Thread.currentThread().getName()+"*******"+i); } } }}public class ThreadTest1 { public static void main(String[] args) { MyThread1 myThread1 = new MyThread1(); //线程命名 方式2 myThread1.setName("huren"); myThread1.start(); //给主线程命名 Thread.currentThread().setName("zongguanjun"); for (int i = 0; i < 100; i++) { if(i % 2 == 0 ){ //Thread.currentThread().setName("lalala"); 线程命名 System.out.println(Thread.currentThread().getName()+"*******///"+i); } } }}------------------------通过构造器命名线程package com.qyl.springboot.controller;class MyThread1 extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { if(i % 2 == 0 ){ //Thread.currentThread().setName("lalala"); 线程命名 方式1 System.out.println(Thread.currentThread().getName()+"*******"+i); } if(i % 20 == 0){ yield(); } } } //线程命名方式3 通过构造器命名 public MyThread1(String name){ super(name); }}public class ThreadTest1 { public static void main(String[] args) { MyThread1 myThread1 = new MyThread1("sssssss"); //线程命名 方式2 myThread1.setName("huren"); myThread1.start(); //给主线程命名 Thread.currentThread().setName("zongguanjun"); for (int i = 0; i < 100; i++) { if(i % 2 == 0 ){ //Thread.currentThread().setName("lalala"); 线程命名 System.out.println(Thread.currentThread().getName()+"*******///"+i); } } }}
5)yiel ():
释放当前cpu的执行权
6)join ():在线程a中调用线程b的join()方法,此时线程a进入阻塞状态,等b执行完之后,a结束阻塞继续执行
7) stop():强制结束该线程,不推荐使用
8) sleep(lang millitime):当前线程睡眠指定的一段时间
9) isAlive()判断当前线程是否存活
10)property()get,set线程的优先级 1-10 默认5
public void newRunnableMethod () { new Thread(new Runnable() { @Override public void run() { // 存放所有openid List openids = new ArrayList<>(); List usersGuid = new ArrayList<>(); SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false); Task_Info_News_ReadMapper mapper = sqlSession.getMapper(Task_Info_News_ReadMapper.class); try{ // 组装info_news_read 表所需要的数据,并存入数据库中 for(int i = 0; i< list.size();i++){ String strUserGuid = (String)list.get(i).get("strUserGuid"); // 通过临时存放usersGuid,去重(对根据范围查出数据进行去重) if(!usersGuid.contains(strUserGuid)){ usersGuid.add(strUserGuid); // 获取openid Object strOpenid = list.get(i).get("strOpenid"); // 如果openid不为空,则放入openids集合中(用来推送模板消息) if(strOpenid != null){ openids.add(strOpenid.toString()); } list.get(i).put("strGuid", UUID.randomUUID().toString()); list.get(i).put("strNewsGuid",info_News.getStrGuid()); list.get(i).put("strCreator",info_News.getStrCreator()); list.get(i).put("dtCreateTime", info_News.getDtCreateTime()); mapper.insertMap(list.get(i)); } if(i % 1000 == 0 || i == list.size() - 1){ sqlSession.commit(); sqlSession.clearCache(); } } }catch (Exception e) { logger.info("事物已回滚"); loggerErr.info("发布任务失败 ==>" + e.getMessage()); sqlSession.rollback(); e.printStackTrace(); }finally { sqlSession.close(); } PropertiesUtils utils = null; try { utils = new PropertiesUtils("global/param_hexi.properties"); } catch (Exception e) { logger.info("global/param_hexi.properties 文件找不到"); e.printStackTrace(); return; } // 微信模板消息,任务的模板id if(openids.size() > 0){ String template_id = utils.getProperty("template_id"); sendNewsToWebchatUser(template_id, openids, info_News); } } }).start();}
//不同的写法
package com.qyl.java;class MyThreadRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { if (i % 2 == 0){ System.out.println(Thread.currentThread().getName() + "=================" +i); } } }}public class SyncThreadTest { public static void main(String[] args) { MyThreadRunnable m1 = new MyThreadRunnable(); Thread t1 = new Thread(m1); t1.setName("子线程1"); t1.start(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { if (i % 2 != 0){ Thread.currentThread().setName("主线程"); System.out.println(Thread.currentThread().getName() + "=================" +i); } } } }).start(); }}
5.使用同步机制将单例模式中的懒汉式改写为线程安全的
1.效率较低的方式
package com.qyl.java;public class BankTest {}class Bank{ private Bank(){} private static Bank instance = null; public static Bank getInstance(){ //加上synchronized就变成线程安全的了 synchronized () { if (instance == null){ instance = new Bank(); } return instance; } }}
2.效率高点
package com.qyl.java;public class BankTest {}class Bank{ private Bank(){ } private static Bank instance = null; public static Bank getInstance(){ //加上synchronized就变成线程安全的了 if (instance == null) { synchronized (Bank.class) { if (instance == null) { instance = new Bank(); } } } return instance; }}
6.线程死锁问题
1.死锁案例
package com.qyl.java;public class SiSuo { public static void main(String[] args) { StringBuffer s1 = new StringBuffer(); StringBuffer s2 = new StringBuffer(); new Thread(){ @Override public void run() { synchronized (s1){ s1.append("a"); s2.append("1"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s2){ s1.append("b"); s2.append("2"); System.out.println(s1); System.out.println(s2); } } } }.start(); new Thread(new Runnable() { @Override public void run() { synchronized (s2){ s1.append("c"); s2.append("3"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s1){ s1.append("d"); s2.append("4"); System.out.println(s1); System.out.println(s2); } } } }).start(); }}
2.解决线程安全问题三 Lock锁
Inspection ‘在使用阻塞等待获取锁的方式中,必须在try代码块之外,并且在加锁方法与try代码块之间没有任何可能抛出异常的方法调用,避免加锁成功后,在finally中无法解锁。
说明一:如果在lock方法与try代码块之间的方法调用抛出异常,那么无法解锁,造成其它线程无法成功获取锁。
说明二:如果lock方法在try代码块之内,可能由于其它方法抛出异常,导致在finally代码块中,unlock对未加锁的对象解锁,它会调用AQS的tryRelease方法(取决于具体实现类),抛出IllegalMonitorStateException异常。
说明三:在Lock对象的lock方法实现中可能抛出unchecked异常,产生的后果与说明二相同。’ options
package com.qyl.java;import java.util.concurrent.locks.ReentrantLock;class WindowLock implements Runnable{ private int titck = 100; //1.实例化一个lock private ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true){ try { lock.lock(); //2.调用lock() if (titck> 0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" 卖票-----票号码为: " + titck ); titck--; } else { break; } } finally { //调用解锁方法 lock.unlock(); } } }}public class LockTest { public static void main(String[] args) { WindowLock m1 = new WindowLock(); Thread t1 = new Thread(m1); Thread t2 = new Thread(m1); Thread t3 = new Thread(m1); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); }}
7.wait() notify()
1.两个线程交叉打印100以内的数
package com.qyl.springboot.controller;
// 2个线程交叉打印100以内的数字
class WaitNotify implements Runnable{
private int number = 1;
@Override
public void run() {
while (true){
synchronized (this) {
//唤醒全部线程
//notifyAll();
//唤醒线程
notify();
if (number<=100){
//睡眠 不释放线程 不释放锁
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" ---打印了 : "+number);
number++;
//等待 但是释放线程 释放锁
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}
}
}
}
public class WaitNotifyTest {
public static void main(String[] args) {
WaitNotify w1 = new WaitNotify();
Thread t1 = new Thread(w1);
Thread t2 = new Thread(w1);
t1.setName("线程1 +++++: ");
t2.setName("线程2 -----: ");
t1.start();
t2.start();
}
}
2.wait(),notify(), notifyAll()
只能用在同步代码块或者方法中 lock不能用
并且调用者必须是同步监视器
这三个方法是定义在对象Object中的 所以都可以用对象调
3.sleep() 和wait()区别相同点:都可以使得当前线程进入阻塞状态
不同点: 1) Thread类中声明Sleep() ,Object类中声明Wait()
2) sleep()不会释放锁,wait() 会
3.)sleep ()在任何场景都可调用,wait只能在同步代码中调用
package com.qyl.springboot.controller;
public class AccountTest {
public static void main(String[] args) {
//定义初始化的账户
Account account = new Account(1000);
//声明两个对象 去开线程
Customer c1 = new Customer(account);
Customer c2 = new Customer(account);
c1.setName("甲");
c2.setName("乙");
c1.start();
c2.start();
}
}
class Account {
//声明账户余额
private double balance;
//构造器
public Account(double balance) {
this.balance = balance;
}
//往里面存钱的方法
//加synchronize 同步
public synchronized void cunQian (double atm){
if ((atm>0)){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前余额: "+balance);
balance += atm;
System.out.println(Thread.currentThread().getName()+" : 存了 "+atm+" 元,已到账.当前余额为"+balance+"员");
}
}
}
//用户类,继承Thread
class Customer extends Thread{
//注入 Account
private Account account;
//构造器
public Customer(Account account) {
this.account = account;
}
//子类重写父类Run方法
@Override
public void run() {
for (int i = 0; i < 3; i++) {
//调用存钱方法
account.cunQian(1000);
}
}
}
方法二:
package com.qyl.springboot.javaTest;
public class CustomerQyl extends Thread{
private AccountQyl accountQyl;
public CustomerQyl(AccountQyl accountQyl) {
this.accountQyl = accountQyl;
}
@Override
public void run() {
for (int i = 0; i < 4; i++) {
String s = accountQyl.Pay(1000);
System.out.println(Thread.currentThread().getName()+" *** "+s);
}
}
}
package com.qyl.springboot.javaTest;
public class AccountQyl {
private double balance;
public AccountQyl(double balance) {
this.balance = balance;
}
public synchronized String Pay (double atm){
if (atm>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前余额: "+balance);
balance += atm;
System.out.println(Thread.currentThread().getName()+" : 存了 "+atm+" 元,已到账.当前余额为"+balance+"员");
}
return "存钱成功";
}
}
package com.qyl.springboot.javaTest;
public class testSync {
public static void main(String[] args) {
AccountQyl accountQyl = new AccountQyl(300);
CustomerQyl c1 = new CustomerQyl(accountQyl);
CustomerQyl c2 = new CustomerQyl(accountQyl);
c1.setName("甲");
c2.setName("乙");
c1.start();
c2.start();
}
}
2.java 递归
package com.esint.jm.wx_hxpublic.util;
//递归 汉诺塔
public class QylDiGuiTest {
static int times = 0;
public static void move (int num , char source , char dest){
System.out.println("第"+(++times)+"步骤 "+num +" 号盘子从 "+source+" 柱子到 "+dest+"柱子");
}
public static void hnt (int n,char source,char mid,char dest){
if (1 == n){
move(n,source,dest);
}else {
hnt(n-1,source,dest,mid);
move(n,source,dest);
hnt(n-1,mid,source,dest);
}
}
public static void main(String[] args) {
hnt(5,'A','B','C');
}
}



