4.14总结

一、每日一题

203. 移除链表元素 - 力扣(LeetCode) (leetcode-cn.com)

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
 

示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
示例 2:

输入:head = [], val = 1
输出:[]
示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]
 

提示:

列表中的节点数目在范围 [0, 104] 内
1 <= Node.val <= 50
0 <= val <= 50

思路

首先,要完成示例一、二这种特殊情况的判断,用一个while循环,因为链表中所以元素都会被删除,所以链表最后指向的是空。

然后,排除了示例一、二这种情况,最终链表中肯定是有元素留下来。如果该结点的下一个结点的数据域与val相等的值,就把该结点的指针跳过该结点的下一个结点,指向该结点的下一个再下一个结点。如果该结点的下一个结点的数据域不与val的值相同,就移动野指针指向该结点的下一个结点。

最后返回头结点。

代码

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        while(head!=NULL&&head->val==val)
        {
            head=head->next;
        }
        if(head==NULL)
        {
            return head;
        }
        ListNode* p=head;
        while(p->next!=NULL)
        {
            if(p->next->val==val)
            {
                p->next=p->next->next;
            }
            else
            {
                p=p->next;
            }
        }
        return head;
    }
};

 二、Java学习

总结了一下多线程。

线程的生命周期

 

方法1:继承Thread类。总结在笔记本上

方式2:实现Runnable接口

  • 定义一个类MyRunnable实现Runnable接口
  • 在MyRunnable类中重写run()方法
  • 创建MyRunnable()类的对象
  • 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
  • 启动线程

方法二相较于方法一的好处

  • 避免了Java单继承的局限性
  • 适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效的分离,较好的体现了面向对象的思想

线程同步

案例 买票

思路

  1. 定义一个类SellTicket实现Runnable接口,里面定义一个成员变量 private int tickets=100;
  2. 在SellTicket类中重写run()方法实现买票,代码步骤如下

A:判断票数大于0,就买票,并告知是几号窗口卖的票

B:成功卖票后,总票数减一

C:票没有了,也可能有人来问,所以用一个自动循环来让卖票这个动作一直持续下去

  1. 定义一个测试类SellTicketDemo,里面有main方法,代码步骤如下

A:创建SellTicket类的对象

B:创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称

C:启动线程

数据安全问题

  • 是否是多线程环境
  • 是否有共享数据
  • 是否有多条语句操作共享数据

如果三个条件都满足,就肯定会出现数据安全问题。

如何解决数据安全问题?

前面两条我们都改变不了,只有改变第三点。也就是将把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行该多条共享语句。

同步代码块

锁多条语句操作共享数据,可以使用同步代码块实现。

格式

synchronized(任意对象)//相当于给代码加锁,任意对象就可以看成是一把锁
{
    多条语句操作共享数据的代码
}

同步方法的锁对象就是this。

同步静态方法:把synchronized关键字加到静态方法上

格式

修饰符 static synchronized 返回值类型 方法名(方法参数){
    
}

同步静态方法的锁对象是类名.class。

Lock锁

Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作。

  • 获得锁:void lock()
  • 释放锁:void unlock()

Lock是接口,不能直接实例化,因此需要采用它的实现类ReentrantLock来实例化

创建一个ReentrarLock的实例:ReentrantLock()

lock()和unlock()之间的代码有可能会出现问题,导致无论执行是否正确,锁都会被释放掉,因此我们要加一个try...catch...方法。

public class SellTicket implements Runnable{
    private int tickets=100;
    private Lock lock=new ReentrantLock();

    @Override
    public void run() {
        while (true){
            try{
                lock.lock();
                if (tickets>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
                    tickets--;
                }
            }finally {
                lock.unlock();
            }
        }
    }
}
public class SellTicketDemo {
    public static void main(String[] args) {
        SellTicket st=new SellTicket();

        Thread t1=new Thread(st,"No.1");
        Thread t2=new Thread(st,"No.2");
        Thread t3=new Thread(st,"No.3");

        t1.start();
        t2.start();
        t3.start();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值